xref: /reactos/win32ss/user/ntuser/scrollbar.c (revision 139a3d66)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Scrollbars
5  * FILE:             win32ss/user/ntuser/scrollbar.c
6  * PROGRAMER:        Thomas Weidenmueller (w3seek@users.sourceforge.net)
7  *                   Jason Filby (jasonfilby@yahoo.com)
8  */
9 
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserScrollbar);
12 
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 */
20 
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 */
24 
25 #define SCROLL_TIMER   0                /* Scroll timer id */
26 
27   /* Minimum size of the rectangle between the arrows */
28 #define SCROLL_MIN_RECT  4
29 
30   /* Minimum size of the thumb in pixels */
31 #define SCROLL_MIN_THUMB 6
32 
33   /* Overlap between arrows and thumb */
34 #define SCROLL_ARROW_THUMB_OVERLAP 0
35 
36 //
37 //
38 //
39 #define MINTRACKTHUMB    8               /* Minimum size of the rectangle between the arrows */
40 
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
46 
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 */
53 
54 #define CHANGERGSTATE(item, status) \
55   if(Info->rgstate[(item)] != (status)) \
56     Chg = TRUE; \
57   Info->rgstate[(item)] = (status);
58 
59 /* FUNCTIONS *****************************************************************/
60 
61 BOOL APIENTRY
62 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows);
63 
64 static void
65 IntRefeshScrollInterior(PWND pWnd, INT nBar, PSCROLLBARINFO psbi);
66 
67 
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.
73  */
74 static inline void mirror_rect( const RECT *window_rect, RECT *rect )
75 {
76     int width = window_rect->right - window_rect->left;
77     int tmp = rect->left;
78     rect->left = width - rect->right;
79     rect->right = width - tmp;
80 }
81 
82 PSBDATA FASTCALL
83 IntGetSBData(PWND pwnd, INT Bar)
84 {
85    PSBWND pSBWnd;
86    PSBINFO pSBInfo;
87 
88    pSBInfo = pwnd->pSBInfo;
89    switch (Bar)
90    {
91        case SB_HORZ:
92          return &pSBInfo->Horz;
93        case SB_VERT:
94          return &pSBInfo->Vert;
95        case SB_CTL:
96          if ( pwnd->cbwndExtra < (sizeof(SBWND)-sizeof(WND)) )
97          {
98             ERR("IntGetSBData Wrong Extra bytes for CTL Scrollbar!\n");
99             return 0;
100          }
101          pSBWnd = (PSBWND)pwnd;
102          return (PSBDATA)&pSBWnd->SBCalc;
103        default:
104             ERR("IntGetSBData Bad Bar!\n");
105    }
106    return NULL;
107 }
108 
109 BOOL FASTCALL
110 IntGetScrollBarRect (PWND Wnd, INT nBar, RECTL *lprect)
111 {
112    BOOL vertical;
113    *lprect = Wnd->rcClient;
114 
115    RECTL_vOffsetRect( lprect, -Wnd->rcWindow.left, -Wnd->rcWindow.top );
116    if (Wnd->ExStyle & WS_EX_LAYOUTRTL)
117       mirror_rect( &Wnd->rcWindow, lprect );
118 
119    switch (nBar)
120    {
121       case SB_HORZ:
122          lprect->top = lprect->bottom;
123          lprect->bottom += UserGetSystemMetrics (SM_CYHSCROLL);
124          if (Wnd->style & WS_BORDER)
125          {
126             lprect->left--;
127             lprect->right++;
128          }
129          else if (Wnd->style & WS_VSCROLL)
130          {
131             lprect->right++;
132          }
133          vertical = FALSE;
134          break;
135 
136       case SB_VERT:
137          if(Wnd->ExStyle & WS_EX_LEFTSCROLLBAR)
138          {
139             lprect->right = lprect->left;
140             lprect->left -= UserGetSystemMetrics(SM_CXVSCROLL);
141          }
142          else
143          {
144             lprect->left = lprect->right;
145             lprect->right += UserGetSystemMetrics(SM_CXVSCROLL);
146          }
147          if (Wnd->style & WS_BORDER)
148          {
149             lprect->top--;
150             lprect->bottom++;
151          }
152          else if (Wnd->style & WS_HSCROLL)
153          {
154             lprect->bottom++;
155          }
156          vertical = TRUE;
157          break;
158 
159       case SB_CTL:
160          IntGetClientRect (Wnd, lprect);
161          vertical = !!(Wnd->style & SBS_VERT);
162          break;
163 
164       default:
165          return FALSE;
166    }
167 
168    return vertical;
169 }
170 
171 BOOL FASTCALL
172 IntCalculateThumb(PWND Wnd, LONG idObject, PSCROLLBARINFO psbi, PSBDATA pSBData)
173 {
174    INT Thumb, ThumbBox, ThumbPos, cxy, mx;
175    RECTL ClientRect;
176 
177    switch(idObject)
178    {
179       case SB_HORZ:
180          Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
181          cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
182          break;
183       case SB_VERT:
184          Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
185          cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
186          break;
187       case SB_CTL:
188          IntGetClientRect(Wnd, &ClientRect);
189          if(Wnd->style & SBS_VERT)
190          {
191             Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
192             cxy = ClientRect.bottom - ClientRect.top;
193          }
194          else
195          {
196             Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
197             cxy = ClientRect.right - ClientRect.left;
198          }
199          break;
200       default:
201          return FALSE;
202    }
203 
204    ThumbPos = Thumb;
205    /* Calculate Thumb */
206    if(cxy <= (2 * Thumb))
207    {
208       Thumb = cxy / 2;
209       psbi->xyThumbTop = 0;
210       psbi->xyThumbBottom = 0;
211       ThumbPos = Thumb;
212    }
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)))
216    {
217       /* Nothing to scroll */
218       psbi->xyThumbTop = 0;
219       psbi->xyThumbBottom = 0;
220    }
221    else
222    {
223       ThumbBox = pSBData->page ? MINTRACKTHUMB : UserGetSystemMetrics(SM_CXHTHUMB);
224       cxy -= (2 * Thumb);
225       if(cxy >= ThumbBox)
226       {
227          if(pSBData->page)
228          {
229             ThumbBox = max(EngMulDiv(cxy, pSBData->page, pSBData->posMax - pSBData->posMin + 1), ThumbBox);
230          }
231 
232          if(cxy > ThumbBox)
233          {
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);
237             else
238                ThumbPos = Thumb + ThumbBox;
239          }
240 
241          psbi->xyThumbTop = ThumbPos;
242          psbi->xyThumbBottom = ThumbPos + ThumbBox;
243       }
244       else
245       {
246          psbi->xyThumbTop = 0;
247          psbi->xyThumbBottom = 0;
248       }
249    }
250    psbi->dxyLineButton = Thumb;
251 
252    return TRUE;
253 }
254 /*
255 static VOID FASTCALL
256 IntUpdateSBInfo(PWND Window, int wBar)
257 {
258    PSCROLLBARINFO sbi;
259    PSBDATA pSBData;
260 
261    ASSERT(Window);
262    ASSERT(Window->pSBInfo);
263    ASSERT(Window->pSBInfoex);
264 
265    sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
266    pSBData = IntGetSBData(Window, wBar);
267    IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
268    IntCalculateThumb(Window, wBar, sbi, pSBData);
269 }
270 */
271 static BOOL FASTCALL
272 co_IntGetScrollInfo(PWND Window, INT nBar, PSBDATA pSBData, LPSCROLLINFO lpsi)
273 {
274    UINT Mask;
275    LPSCROLLINFO psi;
276 
277    ASSERT_REFS_CO(Window);
278 
279    if(!SBID_IS_VALID(nBar))
280    {
281       EngSetLastError(ERROR_INVALID_PARAMETER);
282       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
283       return FALSE;
284    }
285 
286    if (!Window->pSBInfo)
287    {
288       ERR("IntGetScrollInfo No window scrollbar info!\n");
289       return FALSE;
290    }
291 
292    psi = IntGetScrollInfoFromWindow(Window, nBar);
293 
294    if (lpsi->fMask == SIF_ALL)
295    {
296       Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
297    }
298    else
299    {
300       Mask = lpsi->fMask;
301    }
302 
303    if (0 != (Mask & SIF_PAGE))
304    {
305       lpsi->nPage = psi->nPage;
306    }
307 
308    if (0 != (Mask & SIF_POS))
309    {
310       lpsi->nPos = psi->nPos;
311    }
312 
313    if (0 != (Mask & SIF_RANGE))
314    {
315       lpsi->nMin = psi->nMin;
316       lpsi->nMax = psi->nMax;
317    }
318 
319    if (0 != (Mask & SIF_TRACKPOS))
320    {
321       lpsi->nTrackPos = psi->nTrackPos;
322    }
323 
324    return TRUE;
325 }
326 
327 BOOL FASTCALL
328 NEWco_IntGetScrollInfo(
329   PWND pWnd,
330   INT nBar,
331   PSBDATA pSBData,
332   LPSCROLLINFO lpsi)
333 {
334   UINT Mask;
335   PSBTRACK pSBTrack = pWnd->head.pti->pSBTrack;
336 
337   if (!SBID_IS_VALID(nBar))
338   {
339      EngSetLastError(ERROR_INVALID_PARAMETER);
340      ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
341      return FALSE;
342   }
343 
344   if (!pWnd->pSBInfo || !pSBTrack) return FALSE;
345 
346   Mask = lpsi->fMask;
347 
348   if (0 != (Mask & SIF_PAGE))
349   {
350      lpsi->nPage = pSBData->page;
351   }
352 
353   if (0 != (Mask & SIF_POS))
354   {
355      lpsi->nPos = pSBData->pos;
356   }
357 
358   if (0 != (Mask & SIF_RANGE))
359   {
360      lpsi->nMin = pSBData->posMin;
361      lpsi->nMax = pSBData->posMax;
362   }
363 
364   if (0 != (Mask & SIF_TRACKPOS))
365   {
366      if ( pSBTrack &&
367           pSBTrack->nBar == nBar &&
368           pSBTrack->spwndTrack == pWnd )
369         lpsi->nTrackPos = pSBTrack->posNew;
370      else
371         lpsi->nTrackPos = pSBData->pos;
372   }
373   return (Mask & SIF_ALL) !=0;
374 }
375 
376 /*************************************************************************
377  *           SCROLL_GetScrollBarInfo
378  *
379  * Internal helper for the API function
380  *
381  * PARAMS
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
385  *
386  * RETURNS
387  *    FALSE if failed
388  */
389 #if 0
390 static BOOL SCROLL_GetScrollBarInfo(HWND hwnd, LONG idObject, LPSCROLLBARINFO info)
391 {
392     LPSCROLLBAR_INFO infoPtr;
393     INT nBar;
394     INT nDummy;
395     DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
396     BOOL pressed;
397     RECT rect;
398 
399     switch (idObject)
400     {
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;
405     }
406 
407     /* handle invalid data structure */
408     if (info->cbSize != sizeof(*info))
409         return FALSE;
410 
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);
416 
417     info->xyThumbBottom = info->xyThumbTop + info->dxyLineButton;
418 
419     infoPtr = SCROLL_GetInternalInfo(hwnd, nBar, TRUE);
420     if (!infoPtr)
421         return FALSE;
422 
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))
429     {
430         if (!(info->rgstate[0] & STATE_SYSTEM_INVISIBLE))
431             info->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
432         else
433             info->rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
434     }
435     if (nBar == SB_CTL && !IsWindowEnabled(hwnd))
436         info->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
437 
438     pressed = ((nBar == SB_VERT) == SCROLL_trackVertical && GetCapture() == hwnd);
439 
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;
446 
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;
453 
454     /* Thumb state */
455     info->rgstate[3] = 0;
456     if (pressed && SCROLL_trackHitTest == SCROLL_THUMB)
457         info->rgstate[3] |= STATE_SYSTEM_PRESSED;
458 
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;
465 
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;
472 
473     return TRUE;
474 }
475 #endif
476 static DWORD FASTCALL
477 co_IntSetScrollInfo(PWND Window, INT nBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
478 {
479    /*
480     * Update the scrollbar state and set action flags according to
481     * what has to be done graphics wise.
482     */
483 
484    LPSCROLLINFO Info;
485    PSCROLLBARINFO psbi;
486    UINT new_flags;
487    INT action = 0;
488    PSBDATA pSBData;
489    DWORD OldPos = 0;
490    BOOL bChangeParams = FALSE; /* Don't show/hide scrollbar if params don't change */
491    UINT MaxPage;
492    int MaxPos;
493 
494    ASSERT_REFS_CO(Window);
495 
496    if(!SBID_IS_VALID(nBar))
497    {
498       EngSetLastError(ERROR_INVALID_PARAMETER);
499       ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar);
500       return FALSE;
501    }
502 
503    if(!co_IntCreateScrollBars(Window))
504    {
505       return FALSE;
506    }
507 
508    if (lpsi->cbSize != sizeof(SCROLLINFO) &&
509          lpsi->cbSize != (sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos)))
510    {
511       EngSetLastError(ERROR_INVALID_PARAMETER);
512       return 0;
513    }
514    if (lpsi->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL | SIF_PREVIOUSPOS))
515    {
516       EngSetLastError(ERROR_INVALID_PARAMETER);
517       return 0;
518    }
519 
520    psbi = IntGetScrollbarInfoFromWindow(Window, nBar);
521    Info = IntGetScrollInfoFromWindow(Window, nBar);
522    pSBData = IntGetSBData(Window, nBar);
523 
524    /* Set the page size */
525    if (lpsi->fMask & SIF_PAGE)
526    {
527       if (Info->nPage != lpsi->nPage)
528       {
529          Info->nPage = lpsi->nPage;
530          pSBData->page = lpsi->nPage;
531          bChangeParams = TRUE;
532       }
533    }
534 
535    /* Set the scroll pos */
536    if (lpsi->fMask & SIF_POS)
537    {
538       if (Info->nPos != lpsi->nPos)
539       {
540          OldPos = Info->nPos;
541          Info->nPos = lpsi->nPos;
542          pSBData->pos = lpsi->nPos;
543       }
544    }
545 
546    /* Set the scroll range */
547    if (lpsi->fMask & SIF_RANGE)
548    {
549       if (lpsi->nMin > lpsi->nMax)
550       {
551          Info->nMin = lpsi->nMin;
552          Info->nMax = lpsi->nMin;
553          pSBData->posMin = lpsi->nMin;
554          pSBData->posMax = lpsi->nMin;
555          bChangeParams = TRUE;
556       }
557       else if (Info->nMin != lpsi->nMin || Info->nMax != lpsi->nMax)
558       {
559          Info->nMin = lpsi->nMin;
560          Info->nMax = lpsi->nMax;
561          pSBData->posMin = lpsi->nMin;
562          pSBData->posMax = lpsi->nMax;
563          bChangeParams = TRUE;
564       }
565    }
566 
567    /* Make sure the page size is valid */
568    MaxPage = abs(Info->nMax - Info->nMin) + 1;
569    if (Info->nPage > MaxPage)
570    {
571       pSBData->page = Info->nPage = MaxPage;
572    }
573 
574    /* Make sure the pos is inside the range */
575    MaxPos = Info->nMax + 1 - (int)max(Info->nPage, 1);
576    ASSERT(MaxPos >= Info->nMin);
577    if (Info->nPos < Info->nMin)
578    {
579       pSBData->pos = Info->nPos = Info->nMin;
580    }
581    else if (Info->nPos > MaxPos)
582    {
583       pSBData->pos = Info->nPos = MaxPos;
584    }
585 
586    /*
587     * Don't change the scrollbar state if SetScrollInfo is just called
588     * with SIF_DISABLENOSCROLL
589     */
590    if (!(lpsi->fMask & SIF_ALL))
591    {
592       //goto done;
593       return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
594    }
595 
596    /* Check if the scrollbar should be hidden or disabled */
597    if (lpsi->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
598    {
599       new_flags = Window->pSBInfo->WSBflags;
600       if (Info->nMin >= (int)(Info->nMax - max(Info->nPage - 1, 0)))
601       {
602          /* Hide or disable scroll-bar */
603          if (lpsi->fMask & SIF_DISABLENOSCROLL)
604          {
605             new_flags = ESB_DISABLE_BOTH;
606             bChangeParams = TRUE;
607          }
608          else if ((nBar != SB_CTL) && bChangeParams)
609          {
610             action = SA_SSI_HIDE;
611          }
612       }
613       else /* Show and enable scroll-bar only if no page only changed. */
614       if (lpsi->fMask != SIF_PAGE)
615       {
616          if ((nBar != SB_CTL) && bChangeParams)
617          {
618             new_flags = ESB_ENABLE_BOTH;
619             action |= SA_SSI_SHOW;
620          }
621          else if (nBar == SB_CTL)
622          {
623             new_flags = ESB_ENABLE_BOTH;
624          }
625       }
626 
627       if (Window->pSBInfo->WSBflags != new_flags) /* Check arrow flags */
628       {
629          Window->pSBInfo->WSBflags = new_flags;
630          action |= SA_SSI_REPAINT_ARROWS;
631       }
632    }
633 
634 //done:
635    if ( action & SA_SSI_HIDE )
636    {
637       co_UserShowScrollBar(Window, nBar, FALSE, FALSE);
638    }
639    else
640    {
641       if ( action & SA_SSI_SHOW )
642          if ( co_UserShowScrollBar(Window, nBar, TRUE, TRUE) )
643             return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos; /* SetWindowPos() already did the painting */
644       if (bRedraw)
645       {
646          if (action & SA_SSI_REPAINT_ARROWS)
647          {  // Redraw the entire bar.
648             RECTL UpdateRect = psbi->rcScrollBar;
649             UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
650             UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
651             UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
652             UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
653             co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
654          }
655          else
656          {
657             // Redraw only the interior part of the bar.
658             IntRefeshScrollInterior(Window, nBar, psbi);
659          }
660       } // FIXME: Arrows
661 /*      else if( action & SA_SSI_REPAINT_ARROWS )
662       {
663          RECTL UpdateRect = psbi->rcScrollBar;
664          UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
665          UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
666          UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
667          UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
668          co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
669       }
670 */   }
671 
672    if (bChangeParams && (nBar == SB_HORZ || nBar == SB_VERT) && (lpsi->fMask & SIF_DISABLENOSCROLL))
673    {
674        IntEnableScrollBar(nBar == SB_HORZ, psbi, Window->pSBInfo->WSBflags);
675    }
676 
677    /* Return current position */
678    return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
679 }
680 
681 BOOL FASTCALL
682 co_IntGetScrollBarInfo(PWND Window, LONG idObject, PSCROLLBARINFO psbi)
683 {
684    INT Bar;
685    PSCROLLBARINFO sbi;
686    PSBDATA pSBData;
687    ASSERT_REFS_CO(Window);
688 
689    Bar = SBOBJ_TO_SBID(idObject);
690 
691    if(!SBID_IS_VALID(Bar))
692    {
693       EngSetLastError(ERROR_INVALID_PARAMETER);
694       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
695       return FALSE;
696    }
697 
698    if(!co_IntCreateScrollBars(Window))
699    {
700       ERR("Failed to create scrollbars for window.\n");
701       return FALSE;
702    }
703 
704    sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
705    pSBData = IntGetSBData(Window, Bar);
706 
707    IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
708    IntCalculateThumb(Window, Bar, sbi, pSBData);
709 
710     /* Scroll bar state */
711     psbi->rgstate[0] = 0;
712     if ((Bar == SB_HORZ && !(Window->style & WS_HSCROLL))
713         || (Bar == SB_VERT && !(Window->style & WS_VSCROLL)))
714         psbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
715     if (pSBData->posMin >= pSBData->posMax - max(pSBData->page - 1, 0))
716     {
717         if (!(psbi->rgstate[0] & STATE_SYSTEM_INVISIBLE))
718             psbi->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
719         else
720             psbi->rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
721     }
722     if (Bar == SB_CTL && !(Window->style & WS_DISABLED))
723         psbi->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
724 
725    RtlCopyMemory(psbi, sbi, sizeof(SCROLLBARINFO));
726 
727    return TRUE;
728 }
729 
730 BOOL FASTCALL
731 co_IntSetScrollBarInfo(PWND Window, LONG idObject, PSETSCROLLBARINFO psbi)
732 {
733    INT Bar;
734    PSCROLLBARINFO sbi;
735    LPSCROLLINFO psi;
736    ASSERT_REFS_CO(Window);
737 
738    Bar = SBOBJ_TO_SBID(idObject);
739 
740    if(!SBID_IS_VALID(Bar))
741    {
742       EngSetLastError(ERROR_INVALID_PARAMETER);
743       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
744       return FALSE;
745    }
746 
747    if(!co_IntCreateScrollBars(Window))
748    {
749       ERR("Failed to create scrollbars for window.\n");
750       return FALSE;
751    }
752 
753    sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
754    psi = IntGetScrollInfoFromWindow(Window, Bar);
755 
756    psi->nTrackPos = psbi->nTrackPos;
757    sbi->reserved  = psbi->reserved;
758    RtlCopyMemory(&sbi->rgstate, &psbi->rgstate, sizeof(psbi->rgstate));
759 
760    return TRUE;
761 }
762 
763 BOOL FASTCALL
764 co_IntCreateScrollBars(PWND Window)
765 {
766    PSCROLLBARINFO psbi;
767    PSBDATA pSBData;
768    ULONG Size, s;
769    INT i;
770 
771    ASSERT_REFS_CO(Window);
772 
773    if (Window->pSBInfo && Window->pSBInfoex)
774    {
775       /* No need to create it anymore */
776       return TRUE;
777    }
778 
779    /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
780    Size = 3 * (sizeof(SBINFOEX));
781    if(!(Window->pSBInfoex = ExAllocatePoolWithTag(PagedPool, Size, TAG_SBARINFO)))
782    {
783       ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
784       return FALSE;
785    }
786 
787    RtlZeroMemory(Window->pSBInfoex, Size);
788 
789    if(!(Window->pSBInfo = DesktopHeapAlloc( Window->head.rpdesk, sizeof(SBINFO))))
790    {
791       ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
792       return FALSE;
793    }
794 
795    RtlZeroMemory(Window->pSBInfo, sizeof(SBINFO));
796    Window->pSBInfo->Vert.posMax = 100;
797    Window->pSBInfo->Horz.posMax = 100;
798 
799    co_WinPosGetNonClientSize(Window,
800                              &Window->rcWindow,
801                              &Window->rcClient);
802 
803    for(s = SB_HORZ; s <= SB_VERT; s++)
804    {
805       psbi = IntGetScrollbarInfoFromWindow(Window, s);
806       psbi->cbSize = sizeof(SCROLLBARINFO);
807       for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
808          psbi->rgstate[i] = 0;
809 
810       pSBData = IntGetSBData(Window, s);
811 
812       IntGetScrollBarRect(Window, s, &(psbi->rcScrollBar));
813       IntCalculateThumb(Window, s, psbi, pSBData);
814    }
815 
816    return TRUE;
817 }
818 
819 BOOL FASTCALL
820 IntDestroyScrollBars(PWND Window)
821 {
822    if (Window->pSBInfo && Window->pSBInfoex)
823    {
824       DesktopHeapFree(Window->head.rpdesk, Window->pSBInfo);
825       Window->pSBInfo = NULL;
826       ExFreePoolWithTag(Window->pSBInfoex, TAG_SBARINFO);
827       Window->pSBInfoex = NULL;
828       return TRUE;
829    }
830    return FALSE;
831 }
832 
833 BOOL APIENTRY
834 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
835 {
836    BOOL Chg = FALSE;
837    switch(wArrows)
838    {
839       case ESB_DISABLE_BOTH:
840          CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
841          CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
842          break;
843       case ESB_DISABLE_RTDN:
844          if(Horz)
845          {
846             CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
847          }
848          else
849          {
850             CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
851          }
852          break;
853       case ESB_DISABLE_LTUP:
854          if(Horz)
855          {
856             CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
857          }
858          else
859          {
860             CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
861          }
862          break;
863       case ESB_ENABLE_BOTH:
864          CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
865          CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
866          break;
867    }
868    return Chg;
869 }
870 
871 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
872 DWORD FASTCALL
873 co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV)
874 {
875    ULONG old_style, set_bits = 0, clear_bits = 0;
876 
877    ASSERT_REFS_CO(Wnd);
878 
879    switch(nBar)
880    {
881       case SB_CTL:
882          {
883             //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
884 
885             co_WinPosShowWindow(Wnd, fShowH ? SW_SHOW : SW_HIDE);
886             return TRUE;
887          }
888       case SB_BOTH:
889       case SB_HORZ:
890          if (fShowH) set_bits |= WS_HSCROLL;
891          else clear_bits |= WS_HSCROLL;
892          if( nBar == SB_HORZ ) break;
893       /* Fall through */
894       case SB_VERT:
895          if (fShowV) set_bits |= WS_VSCROLL;
896          else clear_bits |= WS_VSCROLL;
897          break;
898       default:
899          EngSetLastError(ERROR_INVALID_PARAMETER);
900          return FALSE; /* Nothing to do! */
901    }
902 
903    old_style = IntSetStyle( Wnd, set_bits, clear_bits );
904    if ((old_style & clear_bits) != 0 || (old_style & set_bits) != set_bits)
905    {
906       /////  Is this needed? Was tested w/o!
907       //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
908       //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
909       /////
910          /* Frame has been changed, let the window redraw itself */
911       co_WinPosSetWindowPos( Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
912                            | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
913       return TRUE;
914    }
915    return FALSE; /* no frame changes */
916 }
917 
918 static void
919 IntDrawScrollInterior(PWND pWnd, HDC hDC, INT nBar, BOOL Vertical, PSCROLLBARINFO ScrollBarInfo)
920 {
921    INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
922    INT ThumbTop = ScrollBarInfo->xyThumbTop;
923    RECT Rect;
924    HBRUSH hSaveBrush, hBrush;
925    BOOL TopSelected = FALSE, BottomSelected = FALSE;
926 
927    if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
928       TopSelected = TRUE;
929    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
930       BottomSelected = TRUE;
931 
932    /*
933     * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
934     * The window-owned scrollbars need to call DefWndControlColor
935     * to correctly setup default scrollbar colors
936     */
937    if (nBar == SB_CTL)
938    {
939       hBrush = GetControlBrush( pWnd, hDC, WM_CTLCOLORSCROLLBAR);
940       if (!hBrush)
941          hBrush = IntGetSysColorBrush(COLOR_SCROLLBAR);
942    }
943    else
944    {
945       hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
946    }
947 
948    hSaveBrush = NtGdiSelectBrush(hDC, hBrush);
949 
950    /* Calculate the scroll rectangle */
951    if (Vertical)
952    {
953       Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
954       Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
955       Rect.left = ScrollBarInfo->rcScrollBar.left;
956       Rect.right = ScrollBarInfo->rcScrollBar.right;
957    }
958    else
959    {
960       Rect.top = ScrollBarInfo->rcScrollBar.top;
961       Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
962       Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
963       Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
964    }
965 
966    /* Draw the scroll rectangles and thumb */
967    if (!ScrollBarInfo->xyThumbBottom)
968    {
969       NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
970          Rect.bottom - Rect.top, PATCOPY);
971 
972       /* Cleanup and return */
973       NtGdiSelectBrush(hDC, hSaveBrush);
974       return;
975    }
976 
977    ThumbTop -= ScrollBarInfo->dxyLineButton;
978 
979    if (ScrollBarInfo->dxyLineButton)
980    {
981       if (Vertical)
982       {
983          if (ThumbSize)
984          {
985             NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
986                    ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
987             Rect.top += ThumbTop;
988             NtGdiPatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
989                Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
990             Rect.bottom = Rect.top + ThumbSize;
991          }
992          else
993          {
994             if (ThumbTop)
995             {
996                NtGdiPatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
997                   Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
998             }
999          }
1000       }
1001       else
1002       {
1003          if (ThumbSize)
1004          {
1005             NtGdiPatBlt(hDC, Rect.left, Rect.top, ThumbTop,
1006                Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
1007             Rect.left += ThumbTop;
1008             NtGdiPatBlt(hDC, Rect.left + ThumbSize, Rect.top,
1009                Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
1010                BottomSelected ? BLACKNESS : PATCOPY);
1011             Rect.right = Rect.left + ThumbSize;
1012          }
1013          else
1014          {
1015             if (ThumbTop)
1016             {
1017                NtGdiPatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
1018                   Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
1019             }
1020          }
1021       }
1022    }
1023 
1024    /* Draw the thumb */
1025    if (ThumbSize)
1026       DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
1027 
1028    /* Cleanup */
1029    NtGdiSelectBrush(hDC, hSaveBrush);
1030 }
1031 
1032 
1033 static VOID FASTCALL
1034 IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
1035 {
1036    RECT RectLT, RectRB;
1037    INT ScrollDirFlagLT, ScrollDirFlagRB;
1038 
1039    RectLT = RectRB = ScrollBarInfo->rcScrollBar;
1040    if (Vertical)
1041    {
1042       ScrollDirFlagLT = DFCS_SCROLLUP;
1043       ScrollDirFlagRB = DFCS_SCROLLDOWN;
1044       RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
1045       RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
1046    }
1047    else
1048    {
1049       ScrollDirFlagLT = DFCS_SCROLLLEFT;
1050       ScrollDirFlagRB = DFCS_SCROLLRIGHT;
1051       RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
1052       RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
1053    }
1054 
1055    if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
1056    {
1057       ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
1058    }
1059    if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
1060    {
1061       ScrollDirFlagLT |= DFCS_INACTIVE;
1062    }
1063    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
1064    {
1065       ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
1066    }
1067    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
1068    {
1069       ScrollDirFlagRB |= DFCS_INACTIVE;
1070    }
1071 
1072    DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
1073    DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
1074 }
1075 
1076 static LONG FASTCALL
1077 IntScrollGetObjectId(INT SBType)
1078 {
1079    if (SBType == SB_VERT)
1080        return OBJID_VSCROLL;
1081    if (SBType == SB_HORZ)
1082        return OBJID_HSCROLL;
1083    return OBJID_CLIENT;
1084 }
1085 
1086 static void
1087 IntRefeshScrollInterior(PWND pWnd, INT nBar, PSCROLLBARINFO psbi)
1088 {
1089    HDC hdc;
1090    BOOL Vertical = ((nBar == SB_CTL) ? ((pWnd->style & SBS_VERT) != 0) : (nBar == SB_VERT));
1091 
1092    hdc = UserGetDCEx(pWnd, NULL, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
1093    if (hdc)
1094    {  /* Get updated info. */
1095       co_IntGetScrollBarInfo(pWnd, IntScrollGetObjectId(nBar), psbi);
1096       IntDrawScrollInterior(pWnd, hdc, nBar, Vertical, psbi);
1097       UserReleaseDC(pWnd, hdc, FALSE);
1098    }
1099 }
1100 
1101 void
1102 IntDrawScrollBar(PWND Wnd, HDC DC, INT Bar)
1103 {
1104    //PSBWND pSBWnd;
1105    //INT ThumbSize;
1106    PTHREADINFO pti;
1107    SCROLLBARINFO Info;
1108    BOOL Vertical;
1109 
1110    pti = PsGetCurrentThreadWin32Thread();
1111 
1112   /*
1113    * Get scroll bar info.
1114    */
1115    switch (Bar)
1116    {
1117       case SB_HORZ:
1118         Vertical = FALSE;
1119         break;
1120 
1121       case SB_VERT:
1122         Vertical = TRUE;
1123         break;
1124 
1125       case SB_CTL:
1126         Vertical = (Wnd->style & SBS_VERT) != 0;
1127         break;
1128 
1129       default:
1130         return;
1131    }
1132 
1133    if (!co_IntGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), &Info))
1134    {
1135       return;
1136    }
1137 
1138    if (RECTL_bIsEmptyRect(&Info.rcScrollBar))
1139    {
1140       return;
1141    }
1142 
1143   //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
1144 
1145   /*
1146    * Draw the arrows.
1147    */
1148    if (Info.dxyLineButton)
1149    {
1150       IntDrawScrollArrows(DC, &Info, Vertical);
1151    }
1152 
1153   /*
1154    * Draw the interior.
1155    */
1156    IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
1157 
1158   /*
1159    * If scroll bar has focus, reposition the caret.
1160    */
1161    if ( Wnd == pti->MessageQueue->spwndFocus && Bar == SB_CTL )
1162    {
1163       if (Vertical)
1164       {
1165           co_IntSetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
1166       }
1167       else
1168       {
1169           co_IntSetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
1170       }
1171    }
1172 }
1173 
1174 
1175 LRESULT APIENTRY
1176 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
1177 {
1178    LRESULT lResult = 0;
1179    PWND pWnd;
1180    pWnd = UserGetWindowObject(hWnd);
1181    if (!pWnd) return 0;
1182 
1183    switch(Msg)
1184    {
1185        case WM_ENABLE:
1186        {
1187            if (pWnd->pSBInfo)
1188            {
1189               pWnd->pSBInfo->WSBflags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1190            }
1191        }
1192        break;
1193    }
1194    return lResult;
1195 }
1196 
1197 ////
1198 
1199 BOOL
1200 APIENTRY
1201 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
1202 {
1203    NTSTATUS Status;
1204    SCROLLBARINFO sbi;
1205    PWND Window;
1206    BOOL Ret;
1207    DECLARE_RETURN(BOOL);
1208    USER_REFERENCE_ENTRY Ref;
1209 
1210    TRACE("Enter NtUserGetScrollBarInfo\n");
1211    UserEnterExclusive();
1212 
1213    Status = MmCopyFromCaller(&sbi, psbi, sizeof(SCROLLBARINFO));
1214    if(!NT_SUCCESS(Status) || (sbi.cbSize != sizeof(SCROLLBARINFO)))
1215    {
1216       SetLastNtError(Status);
1217       RETURN(FALSE);
1218    }
1219 
1220    if(!(Window = UserGetWindowObject(hWnd)))
1221    {
1222       RETURN(FALSE);
1223    }
1224 
1225    UserRefObjectCo(Window, &Ref);
1226    Ret = co_IntGetScrollBarInfo(Window, idObject, &sbi);
1227    UserDerefObjectCo(Window);
1228 
1229    Status = MmCopyToCaller(psbi, &sbi, sizeof(SCROLLBARINFO));
1230    if(!NT_SUCCESS(Status))
1231    {
1232       SetLastNtError(Status);
1233       Ret = FALSE;
1234    }
1235 
1236    RETURN( Ret);
1237 
1238 CLEANUP:
1239    TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_);
1240    UserLeave();
1241    END_CLEANUP;
1242 
1243 }
1244 
1245 BOOL
1246 APIENTRY
1247 NtUserSBGetParms(
1248   HWND hWnd,
1249   int fnBar,
1250   PSBDATA pSBData,
1251   LPSCROLLINFO lpsi)
1252 {
1253    PWND Window;
1254    SCROLLINFO psi;
1255    BOOL Ret;
1256    SBDATA SBDataSafe;
1257    DECLARE_RETURN(BOOL);
1258    USER_REFERENCE_ENTRY Ref;
1259 
1260    TRACE("Enter NtUserGetScrollInfo\n");
1261    UserEnterShared();
1262 
1263    _SEH2_TRY
1264    {
1265       RtlCopyMemory(&psi, lpsi, sizeof(SCROLLINFO));
1266       if (pSBData)
1267       {
1268          RtlCopyMemory(&SBDataSafe, pSBData, sizeof(SBDATA));
1269       }
1270    }
1271    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1272    {
1273       ERR("NtUserGetScrollInfo Failed size.\n");
1274       SetLastNtError(_SEH2_GetExceptionCode());
1275       _SEH2_YIELD(RETURN(FALSE));
1276    }
1277    _SEH2_END
1278 
1279    if(!(Window = UserGetWindowObject(hWnd)))
1280    {
1281       ERR("NtUserGetScrollInfo Bad window.\n");
1282       RETURN(FALSE);
1283    }
1284 
1285    UserRefObjectCo(Window, &Ref);
1286    Ret = co_IntGetScrollInfo(Window, fnBar, &SBDataSafe, &psi);
1287    UserDerefObjectCo(Window);
1288 
1289    _SEH2_TRY
1290    {
1291       RtlCopyMemory(lpsi, &psi, sizeof(SCROLLINFO));
1292    }
1293    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1294    {
1295       ERR("NtUserGetScrollInfo Failed copy to user.\n");
1296       SetLastNtError(_SEH2_GetExceptionCode());
1297       _SEH2_YIELD(RETURN(FALSE));
1298    }
1299    _SEH2_END
1300 
1301    RETURN( Ret);
1302 
1303 CLEANUP:
1304    TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_);
1305    UserLeave();
1306    END_CLEANUP;
1307 }
1308 
1309 BOOL
1310 APIENTRY
1311 NtUserEnableScrollBar(
1312    HWND hWnd,
1313    UINT wSBflags,
1314    UINT wArrows)
1315 {
1316    UINT OrigArrows;
1317    PWND Window = NULL;
1318    PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
1319    BOOL Chg = FALSE;
1320    DECLARE_RETURN(BOOL);
1321    USER_REFERENCE_ENTRY Ref;
1322 
1323    TRACE("Enter NtUserEnableScrollBar\n");
1324    UserEnterExclusive();
1325 
1326    if (!(Window = UserGetWindowObject(hWnd)) ||
1327         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
1328    {
1329       RETURN(FALSE);
1330    }
1331    UserRefObjectCo(Window, &Ref);
1332 
1333    if (!co_IntCreateScrollBars(Window))
1334    {
1335       RETURN( FALSE);
1336    }
1337 
1338    OrigArrows = Window->pSBInfo->WSBflags;
1339    Window->pSBInfo->WSBflags = wArrows;
1340 
1341    if (wSBflags == SB_CTL)
1342    {
1343       if ((wArrows == ESB_DISABLE_BOTH || wArrows == ESB_ENABLE_BOTH))
1344          IntEnableWindow(hWnd, (wArrows == ESB_ENABLE_BOTH));
1345 
1346       RETURN(TRUE);
1347    }
1348 
1349    if(wSBflags != SB_BOTH && !SBID_IS_VALID(wSBflags))
1350    {
1351       EngSetLastError(ERROR_INVALID_PARAMETER);
1352       ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags);
1353       RETURN(FALSE);
1354    }
1355 
1356    switch(wSBflags)
1357    {
1358       case SB_BOTH:
1359          InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1360          /* Fall through */
1361       case SB_HORZ:
1362          InfoH = IntGetScrollbarInfoFromWindow(Window, SB_HORZ);
1363          break;
1364       case SB_VERT:
1365          InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1366          break;
1367       default:
1368          RETURN(FALSE);
1369    }
1370 
1371    if(InfoV)
1372       Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
1373 
1374    if(InfoH)
1375       Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
1376 
1377    ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags, wArrows, Chg);
1378 // Done in user32:
1379 //   SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1380 
1381    RETURN( Chg);
1382    if (OrigArrows == wArrows) RETURN( FALSE);
1383    RETURN( TRUE);
1384 
1385 CLEANUP:
1386    if (Window)
1387       UserDerefObjectCo(Window);
1388 
1389    TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_);
1390    UserLeave();
1391    END_CLEANUP;
1392 }
1393 
1394 DWORD
1395 APIENTRY
1396 NtUserSetScrollInfo(
1397    HWND hWnd,
1398    int fnBar,
1399    LPCSCROLLINFO lpsi,
1400    BOOL bRedraw)
1401 {
1402    PWND Window = NULL;
1403    NTSTATUS Status;
1404    SCROLLINFO ScrollInfo;
1405    DECLARE_RETURN(DWORD);
1406    USER_REFERENCE_ENTRY Ref;
1407 
1408    TRACE("Enter NtUserSetScrollInfo\n");
1409    UserEnterExclusive();
1410 
1411    if(!(Window = UserGetWindowObject(hWnd)) ||
1412         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
1413    {
1414       RETURN( 0);
1415    }
1416    UserRefObjectCo(Window, &Ref);
1417 
1418    Status = MmCopyFromCaller(&ScrollInfo, lpsi, sizeof(SCROLLINFO) - sizeof(ScrollInfo.nTrackPos));
1419    if(!NT_SUCCESS(Status))
1420    {
1421       SetLastNtError(Status);
1422       RETURN( 0);
1423    }
1424 
1425    RETURN(co_IntSetScrollInfo(Window, fnBar, &ScrollInfo, bRedraw));
1426 
1427 CLEANUP:
1428    if (Window)
1429       UserDerefObjectCo(Window);
1430 
1431    TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_);
1432    UserLeave();
1433    END_CLEANUP;
1434 
1435 }
1436 
1437 DWORD APIENTRY
1438 NtUserShowScrollBar(HWND hWnd, int nBar, DWORD bShow)
1439 {
1440    PWND Window;
1441    DECLARE_RETURN(DWORD);
1442    DWORD ret;
1443    USER_REFERENCE_ENTRY Ref;
1444 
1445    TRACE("Enter NtUserShowScrollBar\n");
1446    UserEnterExclusive();
1447 
1448    if (!(Window = UserGetWindowObject(hWnd)))
1449    {
1450       RETURN(0);
1451    }
1452 
1453    UserRefObjectCo(Window, &Ref);
1454    ret = co_UserShowScrollBar(Window, nBar, (nBar == SB_VERT) ? 0 : bShow,
1455                                             (nBar == SB_HORZ) ? 0 : bShow);
1456    UserDerefObjectCo(Window);
1457 
1458    RETURN(ret);
1459 
1460 CLEANUP:
1461    TRACE("Leave NtUserShowScrollBar,  ret%lu\n", _ret_);
1462    UserLeave();
1463    END_CLEANUP;
1464 
1465 }
1466 
1467 
1468 //// Ugly NtUser API ////
1469 
1470 BOOL
1471 APIENTRY
1472 NtUserSetScrollBarInfo(
1473    HWND hWnd,
1474    LONG idObject,
1475    SETSCROLLBARINFO *info)
1476 {
1477    PWND Window = NULL;
1478    SETSCROLLBARINFO Safeinfo;
1479    PSCROLLBARINFO sbi;
1480    LPSCROLLINFO psi;
1481    NTSTATUS Status;
1482    LONG Obj;
1483    DECLARE_RETURN(BOOL);
1484    USER_REFERENCE_ENTRY Ref;
1485 
1486    TRACE("Enter NtUserSetScrollBarInfo\n");
1487    UserEnterExclusive();
1488 
1489    if(!(Window = UserGetWindowObject(hWnd)))
1490    {
1491       RETURN( FALSE);
1492    }
1493    UserRefObjectCo(Window, &Ref);
1494 
1495    Obj = SBOBJ_TO_SBID(idObject);
1496    if(!SBID_IS_VALID(Obj))
1497    {
1498       EngSetLastError(ERROR_INVALID_PARAMETER);
1499       ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj);
1500       RETURN( FALSE);
1501    }
1502 
1503    if(!co_IntCreateScrollBars(Window))
1504    {
1505       RETURN(FALSE);
1506    }
1507 
1508    Status = MmCopyFromCaller(&Safeinfo, info, sizeof(SETSCROLLBARINFO));
1509    if(!NT_SUCCESS(Status))
1510    {
1511       SetLastNtError(Status);
1512       RETURN(FALSE);
1513    }
1514 
1515    sbi = IntGetScrollbarInfoFromWindow(Window, Obj);
1516    psi = IntGetScrollInfoFromWindow(Window, Obj);
1517 
1518    psi->nTrackPos = Safeinfo.nTrackPos;
1519    sbi->reserved = Safeinfo.reserved;
1520    RtlCopyMemory(&sbi->rgstate, &Safeinfo.rgstate, sizeof(Safeinfo.rgstate));
1521 
1522    RETURN(TRUE);
1523 
1524 CLEANUP:
1525    if (Window)
1526       UserDerefObjectCo(Window);
1527 
1528    TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_);
1529    UserLeave();
1530    END_CLEANUP;
1531 }
1532 
1533 /* EOF */
1534