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