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