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