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