xref: /reactos/win32ss/user/ntuser/scrollbar.c (revision 40ee59d6)
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    lpsi->fMask &= ~SIF_THEMED;    // Remove Theme bit
280    if(!SBID_IS_VALID(nBar))
281    {
282       EngSetLastError(ERROR_INVALID_PARAMETER);
283       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
284       return FALSE;
285    }
286 
287    if (!Window->pSBInfo)
288    {
289       ERR("IntGetScrollInfo No window scrollbar info!\n");
290       return FALSE;
291    }
292 
293    psi = IntGetScrollInfoFromWindow(Window, nBar);
294 
295    if (lpsi->fMask == SIF_ALL)
296    {
297       Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
298    }
299    else
300    {
301       Mask = lpsi->fMask;
302    }
303 
304    if (0 != (Mask & SIF_PAGE))
305    {
306       lpsi->nPage = psi->nPage;
307    }
308 
309    if (0 != (Mask & SIF_POS))
310    {
311       lpsi->nPos = psi->nPos;
312    }
313 
314    if (0 != (Mask & SIF_RANGE))
315    {
316       lpsi->nMin = psi->nMin;
317       lpsi->nMax = psi->nMax;
318    }
319 
320    if (0 != (Mask & SIF_TRACKPOS))
321    {
322       lpsi->nTrackPos = psi->nTrackPos;
323    }
324 
325    return TRUE;
326 }
327 
328 BOOL FASTCALL
329 NEWco_IntGetScrollInfo(
330   PWND pWnd,
331   INT nBar,
332   PSBDATA pSBData,
333   LPSCROLLINFO lpsi)
334 {
335   UINT Mask;
336   PSBTRACK pSBTrack = pWnd->head.pti->pSBTrack;
337 
338   lpsi->fMask &= ~SIF_THEMED;         // Remove Theme bit
339   if (!SBID_IS_VALID(nBar))
340   {
341      EngSetLastError(ERROR_INVALID_PARAMETER);
342      ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
343      return FALSE;
344   }
345 
346   if (!pWnd->pSBInfo || !pSBTrack) return FALSE;
347 
348   Mask = lpsi->fMask;
349 
350   if (0 != (Mask & SIF_PAGE))
351   {
352      lpsi->nPage = pSBData->page;
353   }
354 
355   if (0 != (Mask & SIF_POS))
356   {
357      lpsi->nPos = pSBData->pos;
358   }
359 
360   if (0 != (Mask & SIF_RANGE))
361   {
362      lpsi->nMin = pSBData->posMin;
363      lpsi->nMax = pSBData->posMax;
364   }
365 
366   if (0 != (Mask & SIF_TRACKPOS))
367   {
368      if ( pSBTrack &&
369           pSBTrack->nBar == nBar &&
370           pSBTrack->spwndTrack == pWnd )
371         lpsi->nTrackPos = pSBTrack->posNew;
372      else
373         lpsi->nTrackPos = pSBData->pos;
374   }
375   return (Mask & SIF_ALL) !=0;
376 }
377 
378 /*************************************************************************
379  *           SCROLL_GetScrollBarInfo
380  *
381  * Internal helper for the API function
382  *
383  * PARAMS
384  *    hwnd     [I]  Handle of window with scrollbar(s)
385  *    idObject [I]  One of OBJID_CLIENT, OBJID_HSCROLL, or OBJID_VSCROLL
386  *    info     [IO] cbSize specifies the size of the structure
387  *
388  * RETURNS
389  *    FALSE if failed
390  */
391 #if 0
392 static BOOL SCROLL_GetScrollBarInfo(HWND hwnd, LONG idObject, LPSCROLLBARINFO info)
393 {
394     LPSCROLLBAR_INFO infoPtr;
395     INT nBar;
396     INT nDummy;
397     DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
398     BOOL pressed;
399     RECT rect;
400 
401     switch (idObject)
402     {
403         case OBJID_CLIENT: nBar = SB_CTL; break;
404         case OBJID_HSCROLL: nBar = SB_HORZ; break;
405         case OBJID_VSCROLL: nBar = SB_VERT; break;
406         default: return FALSE;
407     }
408 
409     /* handle invalid data structure */
410     if (info->cbSize != sizeof(*info))
411         return FALSE;
412 
413     SCROLL_GetScrollBarRect(hwnd, nBar, &info->rcScrollBar, &nDummy,
414                             &info->dxyLineButton, &info->xyThumbTop);
415     /* rcScrollBar needs to be in screen coordinates */
416     GetWindowRect(hwnd, &rect);
417     OffsetRect(&info->rcScrollBar, rect.left, rect.top);
418 
419     info->xyThumbBottom = info->xyThumbTop + info->dxyLineButton;
420 
421     infoPtr = SCROLL_GetInternalInfo(hwnd, nBar, TRUE);
422     if (!infoPtr)
423         return FALSE;
424 
425     /* Scroll bar state */
426     info->rgstate[0] = 0;
427     if ((nBar == SB_HORZ && !(style & WS_HSCROLL))
428         || (nBar == SB_VERT && !(style & WS_VSCROLL)))
429         info->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
430     if (infoPtr->minVal >= infoPtr->maxVal - max(infoPtr->page - 1, 0))
431     {
432         if (!(info->rgstate[0] & STATE_SYSTEM_INVISIBLE))
433             info->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
434         else
435             info->rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
436     }
437     if (nBar == SB_CTL && !IsWindowEnabled(hwnd))
438         info->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
439 
440     pressed = ((nBar == SB_VERT) == SCROLL_trackVertical && GetCapture() == hwnd);
441 
442     /* Top/left arrow button state. MSDN says top/right, but I don't believe it */
443     info->rgstate[1] = 0;
444     if (pressed && SCROLL_trackHitTest == SCROLL_TOP_ARROW)
445         info->rgstate[1] |= STATE_SYSTEM_PRESSED;
446     if (infoPtr->flags & ESB_DISABLE_LTUP)
447         info->rgstate[1] |= STATE_SYSTEM_UNAVAILABLE;
448 
449     /* Page up/left region state. MSDN says up/right, but I don't believe it */
450     info->rgstate[2] = 0;
451     if (infoPtr->curVal == infoPtr->minVal)
452         info->rgstate[2] |= STATE_SYSTEM_INVISIBLE;
453     if (pressed && SCROLL_trackHitTest == SCROLL_TOP_RECT)
454         info->rgstate[2] |= STATE_SYSTEM_PRESSED;
455 
456     /* Thumb state */
457     info->rgstate[3] = 0;
458     if (pressed && SCROLL_trackHitTest == SCROLL_THUMB)
459         info->rgstate[3] |= STATE_SYSTEM_PRESSED;
460 
461     /* Page down/right region state. MSDN says down/left, but I don't believe it */
462     info->rgstate[4] = 0;
463     if (infoPtr->curVal >= infoPtr->maxVal - 1)
464         info->rgstate[4] |= STATE_SYSTEM_INVISIBLE;
465     if (pressed && SCROLL_trackHitTest == SCROLL_BOTTOM_RECT)
466         info->rgstate[4] |= STATE_SYSTEM_PRESSED;
467 
468     /* Bottom/right arrow button state. MSDN says bottom/left, but I don't believe it */
469     info->rgstate[5] = 0;
470     if (pressed && SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW)
471         info->rgstate[5] |= STATE_SYSTEM_PRESSED;
472     if (infoPtr->flags & ESB_DISABLE_RTDN)
473         info->rgstate[5] |= STATE_SYSTEM_UNAVAILABLE;
474 
475     return TRUE;
476 }
477 #endif
478 static DWORD FASTCALL
479 co_IntSetScrollInfo(PWND Window, INT nBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
480 {
481    /*
482     * Update the scrollbar state and set action flags according to
483     * what has to be done graphics wise.
484     */
485 
486    LPSCROLLINFO Info;
487    PSCROLLBARINFO psbi;
488    UINT new_flags;
489    INT action = 0;
490    PSBDATA pSBData;
491    DWORD OldPos = 0, CurrentPos = 0;
492    BOOL bChangeParams = FALSE; /* Don't show/hide scrollbar if params don't change */
493    UINT MaxPage;
494    int MaxPos;
495    /* [0] = HORZ, [1] = VERT */
496    static PWND PrevHwnd[2] = { 0 };
497    static DWORD PrevPos[2] = { 0 };
498 
499    ASSERT_REFS_CO(Window);
500 
501    if(!SBID_IS_VALID(nBar))
502    {
503       EngSetLastError(ERROR_INVALID_PARAMETER);
504       ERR("Trying to set scrollinfo for unknown scrollbar type %d", nBar);
505       return FALSE;
506    }
507 
508    if(!co_IntCreateScrollBars(Window))
509    {
510       return FALSE;
511    }
512 
513    if (lpsi->cbSize != sizeof(SCROLLINFO) &&
514          lpsi->cbSize != (sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos)))
515    {
516       EngSetLastError(ERROR_INVALID_PARAMETER);
517       return 0;
518    }
519    if ((lpsi->fMask & ~SIF_THEMED) & ~(SIF_ALL | SIF_DISABLENOSCROLL | SIF_PREVIOUSPOS))
520    {
521       EngSetLastError(ERROR_INVALID_PARAMETER);
522       return 0;
523    }
524 
525    psbi = IntGetScrollbarInfoFromWindow(Window, nBar);
526    Info = IntGetScrollInfoFromWindow(Window, nBar);
527    pSBData = IntGetSBData(Window, nBar);
528 
529    /* Set the page size */
530    if (lpsi->fMask & SIF_PAGE)
531    {
532       if (Info->nPage != lpsi->nPage)
533       {
534          Info->nPage = lpsi->nPage;
535          pSBData->page = lpsi->nPage;
536          bChangeParams = TRUE;
537       }
538    }
539 
540    /* Set the scroll pos */
541    if (lpsi->fMask & SIF_POS)
542    {
543       if (Info->nPos != lpsi->nPos)
544       {
545          OldPos = Info->nPos;
546          Info->nPos = lpsi->nPos;
547          pSBData->pos = lpsi->nPos;
548       }
549    }
550 
551    /* Set the scroll range */
552    if (lpsi->fMask & SIF_RANGE)
553    {
554       if (lpsi->nMin > lpsi->nMax)
555       {
556          Info->nMin = lpsi->nMin;
557          Info->nMax = lpsi->nMin;
558          pSBData->posMin = lpsi->nMin;
559          pSBData->posMax = lpsi->nMin;
560          bChangeParams = TRUE;
561       }
562       else if (Info->nMin != lpsi->nMin || Info->nMax != lpsi->nMax)
563       {
564          Info->nMin = lpsi->nMin;
565          Info->nMax = lpsi->nMax;
566          pSBData->posMin = lpsi->nMin;
567          pSBData->posMax = lpsi->nMax;
568          bChangeParams = TRUE;
569       }
570    }
571 
572    /* Make sure the page size is valid */
573    MaxPage = abs(Info->nMax - Info->nMin) + 1;
574    if (Info->nPage > MaxPage)
575    {
576       pSBData->page = Info->nPage = MaxPage;
577    }
578 
579    /* Make sure the pos is inside the range */
580    MaxPos = Info->nMax + 1 - (int)max(Info->nPage, 1);
581    ASSERT(MaxPos >= Info->nMin);
582    if (Info->nPos < Info->nMin)
583    {
584       pSBData->pos = Info->nPos = Info->nMin;
585    }
586    else if (Info->nPos > MaxPos)
587    {
588       pSBData->pos = Info->nPos = MaxPos;
589    }
590 
591    /*
592     * Don't change the scrollbar state if SetScrollInfo is just called
593     * with SIF_DISABLENOSCROLL
594     */
595    if (!(lpsi->fMask & SIF_ALL))
596    {
597       //goto done;
598       return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
599    }
600 
601    /* Check if the scrollbar should be hidden or disabled */
602    if (lpsi->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
603    {
604       new_flags = Window->pSBInfo->WSBflags;
605       if (Info->nMin + (int)max(Info->nPage, 1) > Info->nMax)
606       {
607          /* Hide or disable scroll-bar */
608          if (lpsi->fMask & SIF_DISABLENOSCROLL)
609          {
610             new_flags = ESB_DISABLE_BOTH;
611             bChangeParams = TRUE;
612          }
613          else if ((nBar != SB_CTL) && bChangeParams)
614          {
615             action = SA_SSI_HIDE;
616          }
617       }
618       else /* Show and enable scroll-bar only if no page only changed. */
619       if ((lpsi->fMask & ~SIF_THEMED) != SIF_PAGE)
620       {
621          if ((nBar != SB_CTL) && bChangeParams)
622          {
623             new_flags = ESB_ENABLE_BOTH;
624             action |= SA_SSI_SHOW;
625          }
626          else if (nBar == SB_CTL)
627          {
628             new_flags = ESB_ENABLE_BOTH;
629          }
630       }
631 
632       if (Window->pSBInfo->WSBflags != new_flags) /* Check arrow flags */
633       {
634          Window->pSBInfo->WSBflags = new_flags;
635          action |= SA_SSI_REPAINT_ARROWS;
636       }
637    }
638 
639 //done:
640    if ( action & SA_SSI_HIDE )
641    {
642       co_UserShowScrollBar(Window, nBar, FALSE, FALSE);
643    }
644    else
645    {
646       if ( action & SA_SSI_SHOW )
647          if ( co_UserShowScrollBar(Window, nBar, TRUE, TRUE) )
648             return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos; /* SetWindowPos() already did the painting */
649       if (bRedraw)
650       {
651          if (!(lpsi->fMask & SIF_THEMED)) /* Not Using Themes */
652          {
653             TRACE("Not using themes.\n");
654             if (action & SA_SSI_REPAINT_ARROWS)
655             {
656                // Redraw the entire bar.
657                RECTL UpdateRect = psbi->rcScrollBar;
658                UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
659                UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
660                UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
661                UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
662                co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
663             }
664             else
665             {
666                // Redraw only the interior part of the bar.
667                IntRefeshScrollInterior(Window, nBar, psbi);
668             }
669          }
670          else  /* Using Themes */
671          {
672             RECTL UpdateRect = psbi->rcScrollBar;
673             TRACE("Using themes.\n");
674             UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
675             UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
676             UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
677             UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
678             /* Just paint the interior and not the arrows. */
679             if (!(action & SA_SSI_REPAINT_ARROWS))
680             {
681                if (nBar == SB_HORZ)
682                {
683                   UpdateRect.left += psbi->dxyLineButton;
684                   UpdateRect.right -= psbi->dxyLineButton;
685                }
686                if (nBar == SB_VERT)
687                {
688                   UpdateRect.top += psbi->dxyLineButton;
689                   UpdateRect.bottom -= psbi->dxyLineButton;
690                }
691             }
692             CurrentPos = lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
693             /* Check for changes to Window or CurrentPos */
694             if ((Window != PrevHwnd[nBar]) || (CurrentPos != PrevPos[nBar]))
695             {
696                 co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
697                 PrevHwnd[nBar] = Window;
698                 PrevPos[nBar] = CurrentPos;
699             }
700          }
701       } // FIXME: Arrows
702 /*      else if( action & SA_SSI_REPAINT_ARROWS )
703       {
704          RECTL UpdateRect = psbi->rcScrollBar;
705          UpdateRect.left -= Window->rcClient.left - Window->rcWindow.left;
706          UpdateRect.right -= Window->rcClient.left - Window->rcWindow.left;
707          UpdateRect.top -= Window->rcClient.top - Window->rcWindow.top;
708          UpdateRect.bottom -= Window->rcClient.top - Window->rcWindow.top;
709          co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
710       }
711 */   }
712 
713    if (bChangeParams && (nBar == SB_HORZ || nBar == SB_VERT) && (lpsi->fMask & SIF_DISABLENOSCROLL))
714    {
715        IntEnableScrollBar(nBar == SB_HORZ, psbi, Window->pSBInfo->WSBflags);
716    }
717 
718    /* Return current position */
719    return lpsi->fMask & SIF_PREVIOUSPOS ? OldPos : pSBData->pos;
720 }
721 
722 BOOL FASTCALL
723 co_IntGetScrollBarInfo(PWND Window, LONG idObject, PSCROLLBARINFO psbi)
724 {
725    INT Bar;
726    PSCROLLBARINFO sbi;
727    PSBDATA pSBData;
728    ASSERT_REFS_CO(Window);
729 
730    Bar = SBOBJ_TO_SBID(idObject);
731 
732    if(!SBID_IS_VALID(Bar))
733    {
734       EngSetLastError(ERROR_INVALID_PARAMETER);
735       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
736       return FALSE;
737    }
738 
739    if(!co_IntCreateScrollBars(Window))
740    {
741       ERR("Failed to create scrollbars for window.\n");
742       return FALSE;
743    }
744 
745    sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
746    pSBData = IntGetSBData(Window, Bar);
747 
748    IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
749    IntCalculateThumb(Window, Bar, sbi, pSBData);
750 
751     /* Scroll bar state */
752     psbi->rgstate[0] = 0;
753     if ((Bar == SB_HORZ && !(Window->style & WS_HSCROLL))
754         || (Bar == SB_VERT && !(Window->style & WS_VSCROLL)))
755         psbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
756     if (pSBData->posMin >= pSBData->posMax - max(pSBData->page - 1, 0))
757     {
758         if (!(psbi->rgstate[0] & STATE_SYSTEM_INVISIBLE))
759             psbi->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
760         else
761             psbi->rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
762     }
763     if (Bar == SB_CTL && !(Window->style & WS_DISABLED))
764         psbi->rgstate[0] |= STATE_SYSTEM_UNAVAILABLE;
765 
766    RtlCopyMemory(psbi, sbi, sizeof(SCROLLBARINFO));
767 
768    return TRUE;
769 }
770 
771 BOOL FASTCALL
772 co_IntSetScrollBarInfo(PWND Window, LONG idObject, PSETSCROLLBARINFO psbi)
773 {
774    INT Bar;
775    PSCROLLBARINFO sbi;
776    LPSCROLLINFO psi;
777    ASSERT_REFS_CO(Window);
778 
779    Bar = SBOBJ_TO_SBID(idObject);
780 
781    if(!SBID_IS_VALID(Bar))
782    {
783       EngSetLastError(ERROR_INVALID_PARAMETER);
784       ERR("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
785       return FALSE;
786    }
787 
788    if(!co_IntCreateScrollBars(Window))
789    {
790       ERR("Failed to create scrollbars for window.\n");
791       return FALSE;
792    }
793 
794    sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
795    psi = IntGetScrollInfoFromWindow(Window, Bar);
796 
797    psi->nTrackPos = psbi->nTrackPos;
798    sbi->reserved  = psbi->reserved;
799    RtlCopyMemory(&sbi->rgstate, &psbi->rgstate, sizeof(psbi->rgstate));
800 
801    return TRUE;
802 }
803 
804 BOOL FASTCALL
805 co_IntCreateScrollBars(PWND Window)
806 {
807    PSCROLLBARINFO psbi;
808    PSBDATA pSBData;
809    ULONG Size, s;
810    INT i;
811 
812    ASSERT_REFS_CO(Window);
813 
814    if (Window->pSBInfo && Window->pSBInfoex)
815    {
816       /* No need to create it anymore */
817       return TRUE;
818    }
819 
820    /* Allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
821    Size = 3 * (sizeof(SBINFOEX));
822    if(!(Window->pSBInfoex = ExAllocatePoolWithTag(PagedPool, Size, TAG_SBARINFO)))
823    {
824       ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
825       return FALSE;
826    }
827 
828    RtlZeroMemory(Window->pSBInfoex, Size);
829 
830    if(!(Window->pSBInfo = DesktopHeapAlloc( Window->head.rpdesk, sizeof(SBINFO))))
831    {
832       ERR("Unable to allocate memory for scrollbar information for window %p\n", Window->head.h);
833       return FALSE;
834    }
835 
836    RtlZeroMemory(Window->pSBInfo, sizeof(SBINFO));
837    Window->pSBInfo->Vert.posMax = 100;
838    Window->pSBInfo->Horz.posMax = 100;
839 
840    co_WinPosGetNonClientSize(Window,
841                              &Window->rcWindow,
842                              &Window->rcClient);
843 
844    for(s = SB_HORZ; s <= SB_VERT; s++)
845    {
846       psbi = IntGetScrollbarInfoFromWindow(Window, s);
847       psbi->cbSize = sizeof(SCROLLBARINFO);
848       for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
849          psbi->rgstate[i] = 0;
850 
851       pSBData = IntGetSBData(Window, s);
852 
853       IntGetScrollBarRect(Window, s, &(psbi->rcScrollBar));
854       IntCalculateThumb(Window, s, psbi, pSBData);
855    }
856 
857    return TRUE;
858 }
859 
860 BOOL FASTCALL
861 IntDestroyScrollBars(PWND Window)
862 {
863    if (Window->pSBInfo && Window->pSBInfoex)
864    {
865       DesktopHeapFree(Window->head.rpdesk, Window->pSBInfo);
866       Window->pSBInfo = NULL;
867       ExFreePoolWithTag(Window->pSBInfoex, TAG_SBARINFO);
868       Window->pSBInfoex = NULL;
869       return TRUE;
870    }
871    return FALSE;
872 }
873 
874 BOOL APIENTRY
875 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
876 {
877    BOOL Chg = FALSE;
878    switch(wArrows)
879    {
880       case ESB_DISABLE_BOTH:
881          CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
882          CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
883          break;
884       case ESB_DISABLE_RTDN:
885          if(Horz)
886          {
887             CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
888          }
889          else
890          {
891             CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
892          }
893          break;
894       case ESB_DISABLE_LTUP:
895          if(Horz)
896          {
897             CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
898          }
899          else
900          {
901             CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
902          }
903          break;
904       case ESB_ENABLE_BOTH:
905          CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
906          CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
907          break;
908    }
909    return Chg;
910 }
911 
912 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
913 DWORD FASTCALL
914 co_UserShowScrollBar(PWND Wnd, int nBar, BOOL fShowH, BOOL fShowV)
915 {
916    ULONG old_style, set_bits = 0, clear_bits = 0;
917 
918    ASSERT_REFS_CO(Wnd);
919 
920    switch(nBar)
921    {
922       case SB_CTL:
923          {
924             //IntUpdateSBInfo(Wnd, SB_CTL); // Is this needed? Was tested w/o!
925 
926             co_WinPosShowWindow(Wnd, fShowH ? SW_SHOW : SW_HIDE);
927             return TRUE;
928          }
929       case SB_BOTH:
930       case SB_HORZ:
931          if (fShowH) set_bits |= WS_HSCROLL;
932          else clear_bits |= WS_HSCROLL;
933          if( nBar == SB_HORZ ) break;
934       /* Fall through */
935       case SB_VERT:
936          if (fShowV) set_bits |= WS_VSCROLL;
937          else clear_bits |= WS_VSCROLL;
938          break;
939       default:
940          EngSetLastError(ERROR_INVALID_PARAMETER);
941          return FALSE; /* Nothing to do! */
942    }
943 
944    old_style = IntSetStyle( Wnd, set_bits, clear_bits );
945    if ((old_style & clear_bits) != 0 || (old_style & set_bits) != set_bits)
946    {
947       /////  Is this needed? Was tested w/o!
948       //if (Wnd->style & WS_HSCROLL) IntUpdateSBInfo(Wnd, SB_HORZ);
949       //if (Wnd->style & WS_VSCROLL) IntUpdateSBInfo(Wnd, SB_VERT);
950       /////
951          /* Frame has been changed, let the window redraw itself */
952       co_WinPosSetWindowPos( Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
953                            | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
954       return TRUE;
955    }
956    return FALSE; /* no frame changes */
957 }
958 
959 static void
960 IntDrawScrollInterior(PWND pWnd, HDC hDC, INT nBar, BOOL Vertical, PSCROLLBARINFO ScrollBarInfo)
961 {
962    INT ThumbSize = ScrollBarInfo->xyThumbBottom - ScrollBarInfo->xyThumbTop;
963    INT ThumbTop = ScrollBarInfo->xyThumbTop;
964    RECT Rect;
965    HBRUSH hSaveBrush, hBrush;
966    BOOL TopSelected = FALSE, BottomSelected = FALSE;
967 
968    if (ScrollBarInfo->rgstate[SCROLL_TOP_RECT] & STATE_SYSTEM_PRESSED)
969       TopSelected = TRUE;
970    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_RECT] & STATE_SYSTEM_PRESSED)
971       BottomSelected = TRUE;
972 
973    /*
974     * Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
975     * The window-owned scrollbars need to call DefWndControlColor
976     * to correctly setup default scrollbar colors
977     */
978    if (nBar == SB_CTL)
979    {
980       hBrush = GetControlBrush( pWnd, hDC, WM_CTLCOLORSCROLLBAR);
981       if (!hBrush)
982          hBrush = IntGetSysColorBrush(COLOR_SCROLLBAR);
983    }
984    else
985    {
986       hBrush = DefWndControlColor(hDC, CTLCOLOR_SCROLLBAR);
987    }
988 
989    hSaveBrush = NtGdiSelectBrush(hDC, hBrush);
990 
991    /* Calculate the scroll rectangle */
992    if (Vertical)
993    {
994       Rect.top = ScrollBarInfo->rcScrollBar.top + ScrollBarInfo->dxyLineButton;
995       Rect.bottom = ScrollBarInfo->rcScrollBar.bottom - ScrollBarInfo->dxyLineButton;
996       Rect.left = ScrollBarInfo->rcScrollBar.left;
997       Rect.right = ScrollBarInfo->rcScrollBar.right;
998    }
999    else
1000    {
1001       Rect.top = ScrollBarInfo->rcScrollBar.top;
1002       Rect.bottom = ScrollBarInfo->rcScrollBar.bottom;
1003       Rect.left = ScrollBarInfo->rcScrollBar.left + ScrollBarInfo->dxyLineButton;
1004       Rect.right = ScrollBarInfo->rcScrollBar.right - ScrollBarInfo->dxyLineButton;
1005    }
1006 
1007    /* Draw the scroll rectangles and thumb */
1008    if (!ScrollBarInfo->xyThumbBottom)
1009    {
1010       NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
1011          Rect.bottom - Rect.top, PATCOPY);
1012 
1013       /* Cleanup and return */
1014       NtGdiSelectBrush(hDC, hSaveBrush);
1015       return;
1016    }
1017 
1018    ThumbTop -= ScrollBarInfo->dxyLineButton;
1019 
1020    if (ScrollBarInfo->dxyLineButton)
1021    {
1022       if (Vertical)
1023       {
1024          if (ThumbSize)
1025          {
1026             NtGdiPatBlt(hDC, Rect.left, Rect.top, Rect.right - Rect.left,
1027                    ThumbTop, TopSelected ? BLACKNESS : PATCOPY);
1028             Rect.top += ThumbTop;
1029             NtGdiPatBlt(hDC, Rect.left, Rect.top + ThumbSize, Rect.right - Rect.left,
1030                Rect.bottom - Rect.top - ThumbSize, BottomSelected ? BLACKNESS : PATCOPY);
1031             Rect.bottom = Rect.top + ThumbSize;
1032          }
1033          else
1034          {
1035             if (ThumbTop)
1036             {
1037                NtGdiPatBlt(hDC, Rect.left, ScrollBarInfo->dxyLineButton,
1038                   Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
1039             }
1040          }
1041       }
1042       else
1043       {
1044          if (ThumbSize)
1045          {
1046             NtGdiPatBlt(hDC, Rect.left, Rect.top, ThumbTop,
1047                Rect.bottom - Rect.top, TopSelected ? BLACKNESS : PATCOPY);
1048             Rect.left += ThumbTop;
1049             NtGdiPatBlt(hDC, Rect.left + ThumbSize, Rect.top,
1050                Rect.right - Rect.left - ThumbSize, Rect.bottom - Rect.top,
1051                BottomSelected ? BLACKNESS : PATCOPY);
1052             Rect.right = Rect.left + ThumbSize;
1053          }
1054          else
1055          {
1056             if (ThumbTop)
1057             {
1058                NtGdiPatBlt(hDC, ScrollBarInfo->dxyLineButton, Rect.top,
1059                   Rect.right - Rect.left, Rect.bottom - Rect.top, PATCOPY);
1060             }
1061          }
1062       }
1063    }
1064 
1065    /* Draw the thumb */
1066    if (ThumbSize)
1067       DrawEdge(hDC, &Rect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
1068 
1069    /* Cleanup */
1070    NtGdiSelectBrush(hDC, hSaveBrush);
1071 }
1072 
1073 
1074 static VOID FASTCALL
1075 IntDrawScrollArrows(HDC hDC, PSCROLLBARINFO ScrollBarInfo, BOOL Vertical)
1076 {
1077    RECT RectLT, RectRB;
1078    INT ScrollDirFlagLT, ScrollDirFlagRB;
1079 
1080    RectLT = RectRB = ScrollBarInfo->rcScrollBar;
1081    if (Vertical)
1082    {
1083       ScrollDirFlagLT = DFCS_SCROLLUP;
1084       ScrollDirFlagRB = DFCS_SCROLLDOWN;
1085       RectLT.bottom = RectLT.top + ScrollBarInfo->dxyLineButton;
1086       RectRB.top = RectRB.bottom - ScrollBarInfo->dxyLineButton;
1087    }
1088    else
1089    {
1090       ScrollDirFlagLT = DFCS_SCROLLLEFT;
1091       ScrollDirFlagRB = DFCS_SCROLLRIGHT;
1092       RectLT.right = RectLT.left + ScrollBarInfo->dxyLineButton;
1093       RectRB.left = RectRB.right - ScrollBarInfo->dxyLineButton;
1094    }
1095 
1096    if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_PRESSED)
1097    {
1098       ScrollDirFlagLT |= DFCS_PUSHED | DFCS_FLAT;
1099    }
1100    if (ScrollBarInfo->rgstate[SCROLL_TOP_ARROW] & STATE_SYSTEM_UNAVAILABLE)
1101    {
1102       ScrollDirFlagLT |= DFCS_INACTIVE;
1103    }
1104    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_PRESSED)
1105    {
1106       ScrollDirFlagRB |= DFCS_PUSHED | DFCS_FLAT;
1107    }
1108    if (ScrollBarInfo->rgstate[SCROLL_BOTTOM_ARROW] & STATE_SYSTEM_UNAVAILABLE)
1109    {
1110       ScrollDirFlagRB |= DFCS_INACTIVE;
1111    }
1112 
1113    DrawFrameControl(hDC, &RectLT, DFC_SCROLL, ScrollDirFlagLT);
1114    DrawFrameControl(hDC, &RectRB, DFC_SCROLL, ScrollDirFlagRB);
1115 }
1116 
1117 static LONG FASTCALL
1118 IntScrollGetObjectId(INT SBType)
1119 {
1120    if (SBType == SB_VERT)
1121        return OBJID_VSCROLL;
1122    if (SBType == SB_HORZ)
1123        return OBJID_HSCROLL;
1124    return OBJID_CLIENT;
1125 }
1126 
1127 static void
1128 IntRefeshScrollInterior(PWND pWnd, INT nBar, PSCROLLBARINFO psbi)
1129 {
1130    HDC hdc;
1131    BOOL Vertical = ((nBar == SB_CTL) ? ((pWnd->style & SBS_VERT) != 0) : (nBar == SB_VERT));
1132 
1133    hdc = UserGetDCEx(pWnd, NULL, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
1134    if (hdc)
1135    {  /* Get updated info. */
1136       co_IntGetScrollBarInfo(pWnd, IntScrollGetObjectId(nBar), psbi);
1137       IntDrawScrollInterior(pWnd, hdc, nBar, Vertical, psbi);
1138       UserReleaseDC(pWnd, hdc, FALSE);
1139    }
1140 }
1141 
1142 void
1143 IntDrawScrollBar(PWND Wnd, HDC DC, INT Bar)
1144 {
1145    //PSBWND pSBWnd;
1146    //INT ThumbSize;
1147    PTHREADINFO pti;
1148    SCROLLBARINFO Info;
1149    BOOL Vertical;
1150 
1151    pti = PsGetCurrentThreadWin32Thread();
1152 
1153   /*
1154    * Get scroll bar info.
1155    */
1156    switch (Bar)
1157    {
1158       case SB_HORZ:
1159         Vertical = FALSE;
1160         break;
1161 
1162       case SB_VERT:
1163         Vertical = TRUE;
1164         break;
1165 
1166       case SB_CTL:
1167         Vertical = (Wnd->style & SBS_VERT) != 0;
1168         break;
1169 
1170       default:
1171         return;
1172    }
1173 
1174    if (!co_IntGetScrollBarInfo(Wnd, IntScrollGetObjectId(Bar), &Info))
1175    {
1176       return;
1177    }
1178 
1179    if (RECTL_bIsEmptyRect(&Info.rcScrollBar))
1180    {
1181       return;
1182    }
1183 
1184   //ThumbSize = pSBWnd->pSBCalc->pxThumbBottom - pSBWnd->pSBCalc->pxThumbTop;
1185 
1186   /*
1187    * Draw the arrows.
1188    */
1189    if (Info.dxyLineButton)
1190    {
1191       IntDrawScrollArrows(DC, &Info, Vertical);
1192    }
1193 
1194   /*
1195    * Draw the interior.
1196    */
1197    IntDrawScrollInterior(Wnd, DC, Bar, Vertical, &Info);
1198 
1199   /*
1200    * If scroll bar has focus, reposition the caret.
1201    */
1202    if ( Wnd == pti->MessageQueue->spwndFocus && Bar == SB_CTL )
1203    {
1204       if (Vertical)
1205       {
1206           co_IntSetCaretPos(Info.rcScrollBar.top + 1, Info.dxyLineButton + 1);
1207       }
1208       else
1209       {
1210           co_IntSetCaretPos(Info.dxyLineButton + 1, Info.rcScrollBar.top + 1);
1211       }
1212    }
1213 }
1214 
1215 
1216 LRESULT APIENTRY
1217 ScrollBarWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
1218 {
1219    LRESULT lResult = 0;
1220    PWND pWnd;
1221    pWnd = UserGetWindowObject(hWnd);
1222    if (!pWnd) return 0;
1223 
1224    switch(Msg)
1225    {
1226        case WM_ENABLE:
1227        {
1228            if (pWnd->pSBInfo)
1229            {
1230               pWnd->pSBInfo->WSBflags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1231            }
1232        }
1233        break;
1234    }
1235    return lResult;
1236 }
1237 
1238 ////
1239 
1240 BOOL
1241 APIENTRY
1242 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
1243 {
1244    NTSTATUS Status;
1245    SCROLLBARINFO sbi;
1246    PWND Window;
1247    BOOL Ret;
1248    DECLARE_RETURN(BOOL);
1249    USER_REFERENCE_ENTRY Ref;
1250 
1251    TRACE("Enter NtUserGetScrollBarInfo\n");
1252    UserEnterExclusive();
1253 
1254    Status = MmCopyFromCaller(&sbi, psbi, sizeof(SCROLLBARINFO));
1255    if(!NT_SUCCESS(Status) || (sbi.cbSize != sizeof(SCROLLBARINFO)))
1256    {
1257       SetLastNtError(Status);
1258       RETURN(FALSE);
1259    }
1260 
1261    if(!(Window = UserGetWindowObject(hWnd)))
1262    {
1263       RETURN(FALSE);
1264    }
1265 
1266    UserRefObjectCo(Window, &Ref);
1267    Ret = co_IntGetScrollBarInfo(Window, idObject, &sbi);
1268    UserDerefObjectCo(Window);
1269 
1270    Status = MmCopyToCaller(psbi, &sbi, sizeof(SCROLLBARINFO));
1271    if(!NT_SUCCESS(Status))
1272    {
1273       SetLastNtError(Status);
1274       Ret = FALSE;
1275    }
1276 
1277    RETURN( Ret);
1278 
1279 CLEANUP:
1280    TRACE("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_);
1281    UserLeave();
1282    END_CLEANUP;
1283 
1284 }
1285 
1286 BOOL
1287 APIENTRY
1288 NtUserSBGetParms(
1289   HWND hWnd,
1290   int fnBar,
1291   PSBDATA pSBData,
1292   LPSCROLLINFO lpsi)
1293 {
1294    PWND Window;
1295    SCROLLINFO psi;
1296    BOOL Ret;
1297    SBDATA SBDataSafe;
1298    DECLARE_RETURN(BOOL);
1299    USER_REFERENCE_ENTRY Ref;
1300 
1301    TRACE("Enter NtUserGetScrollInfo\n");
1302    UserEnterShared();
1303 
1304    _SEH2_TRY
1305    {
1306       RtlCopyMemory(&psi, lpsi, sizeof(SCROLLINFO));
1307       if (pSBData)
1308       {
1309          RtlCopyMemory(&SBDataSafe, pSBData, sizeof(SBDATA));
1310       }
1311    }
1312    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1313    {
1314       ERR("NtUserGetScrollInfo Failed size.\n");
1315       SetLastNtError(_SEH2_GetExceptionCode());
1316       _SEH2_YIELD(RETURN(FALSE));
1317    }
1318    _SEH2_END
1319 
1320    if(!(Window = UserGetWindowObject(hWnd)))
1321    {
1322       ERR("NtUserGetScrollInfo Bad window.\n");
1323       RETURN(FALSE);
1324    }
1325 
1326    UserRefObjectCo(Window, &Ref);
1327    Ret = co_IntGetScrollInfo(Window, fnBar, &SBDataSafe, &psi);
1328    UserDerefObjectCo(Window);
1329 
1330    _SEH2_TRY
1331    {
1332       RtlCopyMemory(lpsi, &psi, sizeof(SCROLLINFO));
1333    }
1334    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1335    {
1336       ERR("NtUserGetScrollInfo Failed copy to user.\n");
1337       SetLastNtError(_SEH2_GetExceptionCode());
1338       _SEH2_YIELD(RETURN(FALSE));
1339    }
1340    _SEH2_END
1341 
1342    RETURN( Ret);
1343 
1344 CLEANUP:
1345    TRACE("Leave NtUserGetScrollInfo, ret=%i\n",_ret_);
1346    UserLeave();
1347    END_CLEANUP;
1348 }
1349 
1350 BOOL
1351 APIENTRY
1352 NtUserEnableScrollBar(
1353    HWND hWnd,
1354    UINT wSBflags,
1355    UINT wArrows)
1356 {
1357    UINT OrigArrows;
1358    PWND Window = NULL;
1359    PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
1360    BOOL Chg = FALSE;
1361    DECLARE_RETURN(BOOL);
1362    USER_REFERENCE_ENTRY Ref;
1363 
1364    TRACE("Enter NtUserEnableScrollBar\n");
1365    UserEnterExclusive();
1366 
1367    if (!(Window = UserGetWindowObject(hWnd)) ||
1368         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
1369    {
1370       RETURN(FALSE);
1371    }
1372    UserRefObjectCo(Window, &Ref);
1373 
1374    if (!co_IntCreateScrollBars(Window))
1375    {
1376       RETURN( FALSE);
1377    }
1378 
1379    OrigArrows = Window->pSBInfo->WSBflags;
1380    Window->pSBInfo->WSBflags = wArrows;
1381 
1382    if (wSBflags == SB_CTL)
1383    {
1384       if ((wArrows == ESB_DISABLE_BOTH || wArrows == ESB_ENABLE_BOTH))
1385          IntEnableWindow(hWnd, (wArrows == ESB_ENABLE_BOTH));
1386 
1387       RETURN(TRUE);
1388    }
1389 
1390    if(wSBflags != SB_BOTH && !SBID_IS_VALID(wSBflags))
1391    {
1392       EngSetLastError(ERROR_INVALID_PARAMETER);
1393       ERR("Trying to set scrollinfo for unknown scrollbar type %u", wSBflags);
1394       RETURN(FALSE);
1395    }
1396 
1397    switch(wSBflags)
1398    {
1399       case SB_BOTH:
1400          InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1401          /* Fall through */
1402       case SB_HORZ:
1403          InfoH = IntGetScrollbarInfoFromWindow(Window, SB_HORZ);
1404          break;
1405       case SB_VERT:
1406          InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
1407          break;
1408       default:
1409          RETURN(FALSE);
1410    }
1411 
1412    if(InfoV)
1413       Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
1414 
1415    if(InfoH)
1416       Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
1417 
1418    ERR("FIXME: EnableScrollBar wSBflags %u wArrows %u Chg %d\n", wSBflags, wArrows, Chg);
1419 // Done in user32:
1420 //   SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1421 
1422    RETURN( Chg);
1423    if (OrigArrows == wArrows) RETURN( FALSE);
1424    RETURN( TRUE);
1425 
1426 CLEANUP:
1427    if (Window)
1428       UserDerefObjectCo(Window);
1429 
1430    TRACE("Leave NtUserEnableScrollBar, ret=%i\n",_ret_);
1431    UserLeave();
1432    END_CLEANUP;
1433 }
1434 
1435 DWORD
1436 APIENTRY
1437 NtUserSetScrollInfo(
1438    HWND hWnd,
1439    int fnBar,
1440    LPCSCROLLINFO lpsi,
1441    BOOL bRedraw)
1442 {
1443    PWND Window = NULL;
1444    NTSTATUS Status;
1445    SCROLLINFO ScrollInfo;
1446    DECLARE_RETURN(DWORD);
1447    USER_REFERENCE_ENTRY Ref;
1448 
1449    TRACE("Enter NtUserSetScrollInfo\n");
1450    UserEnterExclusive();
1451 
1452    if(!(Window = UserGetWindowObject(hWnd)) ||
1453         UserIsDesktopWindow(Window) || UserIsMessageWindow(Window))
1454    {
1455       RETURN( 0);
1456    }
1457    UserRefObjectCo(Window, &Ref);
1458 
1459    Status = MmCopyFromCaller(&ScrollInfo, lpsi, sizeof(SCROLLINFO) - sizeof(ScrollInfo.nTrackPos));
1460    if(!NT_SUCCESS(Status))
1461    {
1462       SetLastNtError(Status);
1463       RETURN( 0);
1464    }
1465 
1466    RETURN(co_IntSetScrollInfo(Window, fnBar, &ScrollInfo, bRedraw));
1467 
1468 CLEANUP:
1469    if (Window)
1470       UserDerefObjectCo(Window);
1471 
1472    TRACE("Leave NtUserSetScrollInfo, ret=%lu\n", _ret_);
1473    UserLeave();
1474    END_CLEANUP;
1475 
1476 }
1477 
1478 DWORD APIENTRY
1479 NtUserShowScrollBar(HWND hWnd, int nBar, DWORD bShow)
1480 {
1481    PWND Window;
1482    DECLARE_RETURN(DWORD);
1483    DWORD ret;
1484    USER_REFERENCE_ENTRY Ref;
1485 
1486    TRACE("Enter NtUserShowScrollBar\n");
1487    UserEnterExclusive();
1488 
1489    if (!(Window = UserGetWindowObject(hWnd)))
1490    {
1491       RETURN(0);
1492    }
1493 
1494    UserRefObjectCo(Window, &Ref);
1495    ret = co_UserShowScrollBar(Window, nBar, (nBar == SB_VERT) ? 0 : bShow,
1496                                             (nBar == SB_HORZ) ? 0 : bShow);
1497    UserDerefObjectCo(Window);
1498 
1499    RETURN(ret);
1500 
1501 CLEANUP:
1502    TRACE("Leave NtUserShowScrollBar,  ret%lu\n", _ret_);
1503    UserLeave();
1504    END_CLEANUP;
1505 
1506 }
1507 
1508 
1509 //// Ugly NtUser API ////
1510 
1511 BOOL
1512 APIENTRY
1513 NtUserSetScrollBarInfo(
1514    HWND hWnd,
1515    LONG idObject,
1516    SETSCROLLBARINFO *info)
1517 {
1518    PWND Window = NULL;
1519    SETSCROLLBARINFO Safeinfo;
1520    PSCROLLBARINFO sbi;
1521    LPSCROLLINFO psi;
1522    NTSTATUS Status;
1523    LONG Obj;
1524    DECLARE_RETURN(BOOL);
1525    USER_REFERENCE_ENTRY Ref;
1526 
1527    TRACE("Enter NtUserSetScrollBarInfo\n");
1528    UserEnterExclusive();
1529 
1530    if(!(Window = UserGetWindowObject(hWnd)))
1531    {
1532       RETURN( FALSE);
1533    }
1534    UserRefObjectCo(Window, &Ref);
1535 
1536    Obj = SBOBJ_TO_SBID(idObject);
1537    if(!SBID_IS_VALID(Obj))
1538    {
1539       EngSetLastError(ERROR_INVALID_PARAMETER);
1540       ERR("Trying to set scrollinfo for unknown scrollbar type %d\n", Obj);
1541       RETURN( FALSE);
1542    }
1543 
1544    if(!co_IntCreateScrollBars(Window))
1545    {
1546       RETURN(FALSE);
1547    }
1548 
1549    Status = MmCopyFromCaller(&Safeinfo, info, sizeof(SETSCROLLBARINFO));
1550    if(!NT_SUCCESS(Status))
1551    {
1552       SetLastNtError(Status);
1553       RETURN(FALSE);
1554    }
1555 
1556    sbi = IntGetScrollbarInfoFromWindow(Window, Obj);
1557    psi = IntGetScrollInfoFromWindow(Window, Obj);
1558 
1559    psi->nTrackPos = Safeinfo.nTrackPos;
1560    sbi->reserved = Safeinfo.reserved;
1561    RtlCopyMemory(&sbi->rgstate, &Safeinfo.rgstate, sizeof(Safeinfo.rgstate));
1562 
1563    RETURN(TRUE);
1564 
1565 CLEANUP:
1566    if (Window)
1567       UserDerefObjectCo(Window);
1568 
1569    TRACE("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_);
1570    UserLeave();
1571    END_CLEANUP;
1572 }
1573 
1574 /* EOF */
1575