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