Remove unneeded include statements.
[wine] / dlls / user / scroll.c
1 /*
2  * Scrollbar control
3  *
4  * Copyright 1993 Martin Ayotte
5  * Copyright 1994, 1996 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "wine/winuser16.h"
28 #include "controls.h"
29 #include "win.h"
30 #include "wine/debug.h"
31 #include "user.h"
32 #include "message.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
35
36 typedef struct
37 {
38     INT   curVal;   /* Current scroll-bar value */
39     INT   minVal;   /* Minimum scroll-bar value */
40     INT   maxVal;   /* Maximum scroll-bar value */
41     INT   page;     /* Page size of scroll bar (Win32) */
42     UINT  flags;    /* EnableScrollBar flags */
43 } SCROLLBAR_INFO, *LPSCROLLBAR_INFO;
44
45
46   /* Minimum size of the rectangle between the arrows */
47 #define SCROLL_MIN_RECT  4
48
49   /* Minimum size of the thumb in pixels */
50 #define SCROLL_MIN_THUMB 6
51
52   /* Overlap between arrows and thumb */
53 #define SCROLL_ARROW_THUMB_OVERLAP 0
54
55   /* Delay (in ms) before first repetition when holding the button down */
56 #define SCROLL_FIRST_DELAY   200
57
58   /* Delay (in ms) between scroll repetitions */
59 #define SCROLL_REPEAT_DELAY  50
60
61   /* Scroll timer id */
62 #define SCROLL_TIMER   0
63
64   /* Scroll-bar hit testing */
65 enum SCROLL_HITTEST
66 {
67     SCROLL_NOWHERE,      /* Outside the scroll bar */
68     SCROLL_TOP_ARROW,    /* Top or left arrow */
69     SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
70     SCROLL_THUMB,        /* Thumb rectangle */
71     SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
72     SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
73 };
74
75  /* What to do after SCROLL_SetScrollInfo() */
76 #define SA_SSI_HIDE             0x0001
77 #define SA_SSI_SHOW             0x0002
78 #define SA_SSI_REFRESH          0x0004
79 #define SA_SSI_REPAINT_ARROWS   0x0008
80
81  /* Thumb-tracking info */
82 static HWND SCROLL_TrackingWin = 0;
83 static INT  SCROLL_TrackingBar = 0;
84 static INT  SCROLL_TrackingPos = 0;
85 static INT  SCROLL_TrackingVal = 0;
86  /* Hit test code of the last button-down event */
87 static enum SCROLL_HITTEST SCROLL_trackHitTest;
88 static BOOL SCROLL_trackVertical;
89
90  /* Is the moving thumb being displayed? */
91 static BOOL SCROLL_MovingThumb = FALSE;
92
93  /* Local functions */
94 static BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar,
95                                     BOOL fShowH, BOOL fShowV );
96 static INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar,
97                                  const SCROLLINFO *info, BOOL bRedraw );
98 static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
99                                     RECT *rect, INT arrowSize,
100                                     INT thumbSize, INT thumbPos,
101                                     UINT flags, BOOL vertical,
102                                     BOOL top_selected, BOOL bottom_selected );
103 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
104
105
106 /*********************************************************************
107  * scrollbar class descriptor
108  */
109 const struct builtin_class_descr SCROLL_builtin_class =
110 {
111     "ScrollBar",            /* name */
112     CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC, /* style  */
113     NULL,                   /* procA (winproc is Unicode only) */
114     ScrollBarWndProc,       /* procW */
115     sizeof(SCROLLBAR_INFO), /* extra */
116     IDC_ARROW,              /* cursor */
117     0                       /* brush */
118 };
119     
120 /***********************************************************************
121  *           SCROLL_ScrollInfoValid
122  *
123  *  Determine if the supplied SCROLLINFO struct is valid.
124  */
125 inline static BOOL SCROLL_ScrollInfoValid(
126 LPSCROLLINFO info /* [in] The SCROLLINFO struct to be tested */)
127 {
128     return !(info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)
129         || (info->cbSize != sizeof(*info)
130             && info->cbSize != sizeof(*info) - sizeof(info->nTrackPos)));
131 }
132
133
134 /***********************************************************************
135  *           SCROLL_GetScrollBarInfo
136  */
137 static SCROLLBAR_INFO *SCROLL_GetScrollBarInfo( HWND hwnd, INT nBar )
138 {
139     SCROLLBAR_INFO *infoPtr;
140     WND *wndPtr = WIN_FindWndPtr( hwnd );
141
142     if (!wndPtr) return NULL;
143     switch(nBar)
144     {
145         case SB_HORZ: infoPtr = (SCROLLBAR_INFO *)wndPtr->pHScroll; break;
146         case SB_VERT: infoPtr = (SCROLLBAR_INFO *)wndPtr->pVScroll; break;
147         case SB_CTL:  infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; break;
148         default:
149             WIN_ReleaseWndPtr( wndPtr );
150             return NULL;
151     }
152
153     if (!infoPtr)  /* Create the info structure if needed */
154     {
155         if ((infoPtr = HeapAlloc( GetProcessHeap(), 0, sizeof(SCROLLBAR_INFO) )))
156         {
157             infoPtr->minVal = infoPtr->curVal = infoPtr->page = 0;
158             infoPtr->maxVal = 100;
159             infoPtr->flags  = ESB_ENABLE_BOTH;
160             if (nBar == SB_HORZ) wndPtr->pHScroll = infoPtr;
161             else wndPtr->pVScroll = infoPtr;
162         }
163     }
164     WIN_ReleaseWndPtr( wndPtr );
165     return infoPtr;
166 }
167
168
169 /***********************************************************************
170  *           SCROLL_GetScrollBarRect
171  *
172  * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
173  * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
174  * 'arrowSize' returns the width or height of an arrow (depending on
175  * the orientation of the scrollbar), 'thumbSize' returns the size of
176  * the thumb, and 'thumbPos' returns the position of the thumb
177  * relative to the left or to the top.
178  * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
179  */
180 static BOOL SCROLL_GetScrollBarRect( HWND hwnd, INT nBar, RECT *lprect,
181                                        INT *arrowSize, INT *thumbSize,
182                                        INT *thumbPos )
183 {
184     INT pixels;
185     BOOL vertical;
186     WND *wndPtr = WIN_FindWndPtr( hwnd );
187
188     switch(nBar)
189     {
190       case SB_HORZ:
191         lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left;
192         lprect->top    = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
193         lprect->right  = wndPtr->rectClient.right - wndPtr->rectWindow.left;
194         lprect->bottom = lprect->top + GetSystemMetrics(SM_CYHSCROLL);
195         if(wndPtr->dwStyle & WS_BORDER) {
196           lprect->left--;
197           lprect->right++;
198         } else if(wndPtr->dwStyle & WS_VSCROLL)
199           lprect->right++;
200         vertical = FALSE;
201         break;
202
203       case SB_VERT:
204         if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
205             lprect->left   = wndPtr->rectClient.left - wndPtr->rectWindow.left - GetSystemMetrics(SM_CXVSCROLL);
206         else
207             lprect->left   = wndPtr->rectClient.right - wndPtr->rectWindow.left;
208         lprect->top    = wndPtr->rectClient.top - wndPtr->rectWindow.top;
209         lprect->right  = lprect->left + GetSystemMetrics(SM_CXVSCROLL);
210         lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
211         if(wndPtr->dwStyle & WS_BORDER) {
212           lprect->top--;
213           lprect->bottom++;
214         } else if(wndPtr->dwStyle & WS_HSCROLL)
215           lprect->bottom++;
216         vertical = TRUE;
217         break;
218
219       case SB_CTL:
220         GetClientRect( hwnd, lprect );
221         vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
222         break;
223
224     default:
225         WIN_ReleaseWndPtr(wndPtr);
226         return FALSE;
227     }
228
229     if (vertical) pixels = lprect->bottom - lprect->top;
230     else pixels = lprect->right - lprect->left;
231
232     if (pixels <= 2*GetSystemMetrics(SM_CXVSCROLL) + SCROLL_MIN_RECT)
233     {
234         if (pixels > SCROLL_MIN_RECT)
235             *arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
236         else
237             *arrowSize = 0;
238         *thumbPos = *thumbSize = 0;
239     }
240     else
241     {
242         SCROLLBAR_INFO *info = SCROLL_GetScrollBarInfo( hwnd, nBar );
243
244         *arrowSize = GetSystemMetrics(SM_CXVSCROLL);
245         pixels -= (2 * (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP));
246
247         if (info->page)
248         {
249             *thumbSize = MulDiv(pixels,info->page,(info->maxVal-info->minVal+1));
250             if (*thumbSize < SCROLL_MIN_THUMB) *thumbSize = SCROLL_MIN_THUMB;
251         }
252         else *thumbSize = GetSystemMetrics(SM_CXVSCROLL);
253
254         if (((pixels -= *thumbSize ) < 0) ||
255             ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH))
256         {
257             /* Rectangle too small or scrollbar disabled -> no thumb */
258             *thumbPos = *thumbSize = 0;
259         }
260         else
261         {
262             INT max = info->maxVal - max( info->page-1, 0 );
263             if (info->minVal >= max)
264                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
265             else
266                 *thumbPos = *arrowSize - SCROLL_ARROW_THUMB_OVERLAP
267                   + MulDiv(pixels, (info->curVal-info->minVal),(max - info->minVal));
268         }
269     }
270     WIN_ReleaseWndPtr(wndPtr);
271     return vertical;
272 }
273
274
275 /***********************************************************************
276  *           SCROLL_GetThumbVal
277  *
278  * Compute the current scroll position based on the thumb position in pixels
279  * from the top of the scroll-bar.
280  */
281 static UINT SCROLL_GetThumbVal( SCROLLBAR_INFO *infoPtr, RECT *rect,
282                                   BOOL vertical, INT pos )
283 {
284     INT thumbSize;
285     INT pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
286
287     if ((pixels -= 2*(GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP)) <= 0)
288         return infoPtr->minVal;
289
290     if (infoPtr->page)
291     {
292         thumbSize = MulDiv(pixels,infoPtr->page,(infoPtr->maxVal-infoPtr->minVal+1));
293         if (thumbSize < SCROLL_MIN_THUMB) thumbSize = SCROLL_MIN_THUMB;
294     }
295     else thumbSize = GetSystemMetrics(SM_CXVSCROLL);
296
297     if ((pixels -= thumbSize) <= 0) return infoPtr->minVal;
298
299     pos = max( 0, pos - (GetSystemMetrics(SM_CXVSCROLL) - SCROLL_ARROW_THUMB_OVERLAP) );
300     if (pos > pixels) pos = pixels;
301
302     if (!infoPtr->page) pos *= infoPtr->maxVal - infoPtr->minVal;
303     else pos *= infoPtr->maxVal - infoPtr->minVal - infoPtr->page + 1;
304     return infoPtr->minVal + ((pos + pixels / 2) / pixels);
305 }
306
307 /***********************************************************************
308  *           SCROLL_PtInRectEx
309  */
310 static BOOL SCROLL_PtInRectEx( LPRECT lpRect, POINT pt, BOOL vertical )
311 {
312     RECT rect = *lpRect;
313
314     if (vertical)
315     {
316         rect.left -= lpRect->right - lpRect->left;
317         rect.right += lpRect->right - lpRect->left;
318     }
319     else
320     {
321         rect.top -= lpRect->bottom - lpRect->top;
322         rect.bottom += lpRect->bottom - lpRect->top;
323     }
324     return PtInRect( &rect, pt );
325 }
326
327 /***********************************************************************
328  *           SCROLL_ClipPos
329  */
330 static POINT SCROLL_ClipPos( LPRECT lpRect, POINT pt )
331 {
332     if( pt.x < lpRect->left )
333         pt.x = lpRect->left;
334     else
335     if( pt.x > lpRect->right )
336         pt.x = lpRect->right;
337
338     if( pt.y < lpRect->top )
339         pt.y = lpRect->top;
340     else
341     if( pt.y > lpRect->bottom )
342         pt.y = lpRect->bottom;
343
344     return pt;
345 }
346
347
348 /***********************************************************************
349  *           SCROLL_HitTest
350  *
351  * Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
352  */
353 static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, INT nBar,
354                                            POINT pt, BOOL bDragging )
355 {
356     INT arrowSize, thumbSize, thumbPos;
357     RECT rect;
358
359     BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
360                                            &arrowSize, &thumbSize, &thumbPos );
361
362     if ( (bDragging && !SCROLL_PtInRectEx( &rect, pt, vertical )) ||
363          (!PtInRect( &rect, pt )) ) return SCROLL_NOWHERE;
364
365     if (vertical)
366     {
367         if (pt.y < rect.top + arrowSize) return SCROLL_TOP_ARROW;
368         if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
369         if (!thumbPos) return SCROLL_TOP_RECT;
370         pt.y -= rect.top;
371         if (pt.y < thumbPos) return SCROLL_TOP_RECT;
372         if (pt.y >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
373     }
374     else  /* horizontal */
375     {
376         if (pt.x < rect.left + arrowSize) return SCROLL_TOP_ARROW;
377         if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
378         if (!thumbPos) return SCROLL_TOP_RECT;
379         pt.x -= rect.left;
380         if (pt.x < thumbPos) return SCROLL_TOP_RECT;
381         if (pt.x >= thumbPos + thumbSize) return SCROLL_BOTTOM_RECT;
382     }
383     return SCROLL_THUMB;
384 }
385
386
387 /***********************************************************************
388  *           SCROLL_DrawArrows
389  *
390  * Draw the scroll bar arrows.
391  */
392 static void SCROLL_DrawArrows( HDC hdc, SCROLLBAR_INFO *infoPtr,
393                                RECT *rect, INT arrowSize, BOOL vertical,
394                                BOOL top_pressed, BOOL bottom_pressed )
395 {
396   RECT r;
397
398   r = *rect;
399   if( vertical )
400     r.bottom = r.top + arrowSize;
401   else
402     r.right = r.left + arrowSize;
403
404   DrawFrameControl( hdc, &r, DFC_SCROLL,
405                     (vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
406                     | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
407                     | (infoPtr->flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
408
409   r = *rect;
410   if( vertical )
411     r.top = r.bottom-arrowSize;
412   else
413     r.left = r.right-arrowSize;
414
415   DrawFrameControl( hdc, &r, DFC_SCROLL,
416                     (vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
417                     | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
418                     | (infoPtr->flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
419 }
420
421 static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
422                                     INT arrowSize, INT thumbSize )
423 {
424   INT pos = SCROLL_TrackingPos;
425   INT max_size;
426
427   if( vertical )
428     max_size = rect->bottom - rect->top;
429   else
430     max_size = rect->right - rect->left;
431
432   max_size -= (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
433
434   if( pos < (arrowSize-SCROLL_ARROW_THUMB_OVERLAP) )
435     pos = (arrowSize-SCROLL_ARROW_THUMB_OVERLAP);
436   else if( pos > max_size )
437     pos = max_size;
438
439   SCROLL_DrawInterior_9x( SCROLL_TrackingWin, hdc, SCROLL_TrackingBar,
440                           rect, arrowSize, thumbSize, pos,
441                           0, vertical, FALSE, FALSE );
442
443   SCROLL_MovingThumb = !SCROLL_MovingThumb;
444 }
445
446 /***********************************************************************
447  *           SCROLL_DrawInterior
448  *
449  * Draw the scroll bar interior (everything except the arrows).
450  */
451 static void SCROLL_DrawInterior_9x( HWND hwnd, HDC hdc, INT nBar,
452                                     RECT *rect, INT arrowSize,
453                                     INT thumbSize, INT thumbPos,
454                                     UINT flags, BOOL vertical,
455                                     BOOL top_selected, BOOL bottom_selected )
456 {
457     RECT r;
458     HPEN hSavePen;
459     HBRUSH hSaveBrush,hBrush;
460
461     /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
462      * The window-owned scrollbars need to call DEFWND_ControlColor
463      * to correctly setup default scrollbar colors
464      */
465     if (nBar == SB_CTL)
466     {
467       hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
468                                      (WPARAM)hdc,(LPARAM)hwnd);
469     }
470     else
471     {
472       hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
473     }
474
475     hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
476     hSaveBrush = SelectObject( hdc, hBrush );
477
478     /* Calculate the scroll rectangle */
479     r = *rect;
480     if (vertical)
481     {
482         r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
483         r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
484     }
485     else
486     {
487         r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
488         r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
489     }
490
491     /* Draw the scroll rectangles and thumb */
492     if (!thumbPos)  /* No thumb to draw */
493     {
494         PatBlt( hdc, r.left, r.top,
495                      r.right - r.left, r.bottom - r.top,
496                      PATCOPY );
497
498         /* cleanup and return */
499         SelectObject( hdc, hSavePen );
500         SelectObject( hdc, hSaveBrush );
501         return;
502     }
503
504     if (vertical)
505     {
506         PatBlt( hdc, r.left, r.top,
507                   r.right - r.left,
508                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
509                   top_selected ? 0x0f0000 : PATCOPY );
510         r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
511         PatBlt( hdc, r.left, r.top + thumbSize,
512                   r.right - r.left,
513                   r.bottom - r.top - thumbSize,
514                   bottom_selected ? 0x0f0000 : PATCOPY );
515         r.bottom = r.top + thumbSize;
516     }
517     else  /* horizontal */
518     {
519         PatBlt( hdc, r.left, r.top,
520                   thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
521                   r.bottom - r.top,
522                   top_selected ? 0x0f0000 : PATCOPY );
523         r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
524         PatBlt( hdc, r.left + thumbSize, r.top,
525                   r.right - r.left - thumbSize,
526                   r.bottom - r.top,
527                   bottom_selected ? 0x0f0000 : PATCOPY );
528         r.right = r.left + thumbSize;
529     }
530
531     /* Draw the thumb */
532     DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT | BF_MIDDLE  );
533
534     /* cleanup */
535     SelectObject( hdc, hSavePen );
536     SelectObject( hdc, hSaveBrush );
537 }
538
539
540 static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
541                                  RECT *rect, INT arrowSize,
542                                  INT thumbSize, INT thumbPos,
543                                  UINT flags, BOOL vertical,
544                                  BOOL top_selected, BOOL bottom_selected )
545 {
546     RECT r;
547     HPEN hSavePen;
548     HBRUSH hSaveBrush,hBrush;
549     BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
550
551     if (Save_SCROLL_MovingThumb &&
552         (SCROLL_TrackingWin == hwnd) &&
553         (SCROLL_TrackingBar == nBar))
554         SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
555
556       /* Select the correct brush and pen */
557
558     /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
559      * The window-owned scrollbars need to call DEFWND_ControlColor
560      * to correctly setup default scrollbar colors
561      */
562     if (nBar == SB_CTL) {
563         hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
564                                        (WPARAM)hdc,(LPARAM)hwnd);
565     } else {
566         hBrush = DEFWND_ControlColor( hdc, CTLCOLOR_SCROLLBAR );
567     }
568     hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
569     hSaveBrush = SelectObject( hdc, hBrush );
570
571       /* Calculate the scroll rectangle */
572
573     r = *rect;
574     if (vertical)
575     {
576         r.top    += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
577         r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
578     }
579     else
580     {
581         r.left  += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
582         r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
583     }
584
585       /* Draw the scroll bar frame */
586
587       /* Draw the scroll rectangles and thumb */
588
589     if (!thumbPos)  /* No thumb to draw */
590     {
591         PatBlt( hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY );
592
593         /* cleanup and return */
594         SelectObject( hdc, hSavePen );
595         SelectObject( hdc, hSaveBrush );
596         return;
597     }
598
599     if (vertical)
600     {
601         PatBlt( hdc, r.left, r.top, r.right - r.left,
602                 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
603                 top_selected ? 0x0f0000 : PATCOPY );
604         r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
605         PatBlt( hdc, r.left, r.top + thumbSize, r.right - r.left,
606                 r.bottom - r.top - thumbSize,
607                 bottom_selected ? 0x0f0000 : PATCOPY );
608         r.bottom = r.top + thumbSize;
609     }
610     else  /* horizontal */
611     {
612         PatBlt( hdc, r.left, r.top,
613                 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
614                 r.bottom - r.top, top_selected ? 0x0f0000 : PATCOPY );
615         r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
616         PatBlt( hdc, r.left + thumbSize, r.top, r.right - r.left - thumbSize,
617                 r.bottom - r.top, bottom_selected ? 0x0f0000 : PATCOPY );
618         r.right = r.left + thumbSize;
619     }
620
621       /* Draw the thumb */
622
623     SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
624     Rectangle( hdc, r.left+1, r.top+1, r.right-1, r.bottom-1 );
625     DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
626
627     if (Save_SCROLL_MovingThumb &&
628         (SCROLL_TrackingWin == hwnd) &&
629         (SCROLL_TrackingBar == nBar))
630         SCROLL_DrawMovingThumb( hdc, rect, vertical, arrowSize, thumbSize );
631
632     /* cleanup */
633     SelectObject( hdc, hSavePen );
634     SelectObject( hdc, hSaveBrush );
635 }
636
637
638 /***********************************************************************
639  *           SCROLL_DrawScrollBar
640  *
641  * Redraw the whole scrollbar.
642  */
643 void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar,
644                            BOOL arrows, BOOL interior )
645 {
646     INT arrowSize, thumbSize, thumbPos;
647     RECT rect;
648     BOOL vertical;
649     WND *wndPtr = WIN_FindWndPtr( hwnd );
650     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar );
651     BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
652
653     if (!wndPtr || !infoPtr ||
654         ((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
655         ((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) goto END;
656     if (!WIN_IsWindowDrawable( hwnd, FALSE )) goto END;
657     hwnd = wndPtr->hwndSelf;  /* make it a full handle */
658
659     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
660                                         &arrowSize, &thumbSize, &thumbPos );
661
662     /* do not draw if the scrollbar rectangle is empty */
663     if(IsRectEmpty(&rect))
664       goto END;
665
666     if (Save_SCROLL_MovingThumb &&
667         (SCROLL_TrackingWin == hwnd) &&
668         (SCROLL_TrackingBar == nBar))
669         SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
670
671       /* Draw the arrows */
672
673     if (arrows && arrowSize)
674     {
675         if( vertical == SCROLL_trackVertical && GetCapture() == hwnd )
676             SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
677                                (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
678                                (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW) );
679         else
680             SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
681                                                                FALSE, FALSE );
682     }
683     if( interior )
684         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
685                          thumbPos, infoPtr->flags, vertical, FALSE, FALSE );
686
687     if (Save_SCROLL_MovingThumb &&
688         (SCROLL_TrackingWin == hwnd) &&
689         (SCROLL_TrackingBar == nBar))
690         SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize, thumbSize );
691
692     /* if scroll bar has focus, reposition the caret */
693     if(hwnd==GetFocus() && (nBar==SB_CTL))
694     {
695         if (!vertical)
696         {
697             SetCaretPos(thumbPos+1, rect.top+1);
698         }
699         else
700         {
701             SetCaretPos(rect.top+1, thumbPos+1);
702         }
703     }
704
705 END:
706     WIN_ReleaseWndPtr(wndPtr);
707 }
708
709 /***********************************************************************
710  *           SCROLL_DrawSizeGrip
711  *
712  *  Draw the size grip.
713  */
714 static void SCROLL_DrawSizeGrip( HWND hwnd,  HDC hdc)
715 {
716     RECT rc;
717
718     GetClientRect( hwnd, &rc );
719     FillRect( hdc, &rc, GetSysColorBrush(COLOR_SCROLLBAR) );
720     rc.left = max( rc.left, rc.right - GetSystemMetrics(SM_CXVSCROLL) - 1 );
721     rc.top  = max( rc.top, rc.bottom - GetSystemMetrics(SM_CYHSCROLL) - 1 );
722     DrawFrameControl( hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP );
723 }
724
725
726 /***********************************************************************
727  *           SCROLL_RefreshScrollBar
728  *
729  * Repaint the scroll bar interior after a SetScrollRange() or
730  * SetScrollPos() call.
731  */
732 static void SCROLL_RefreshScrollBar( HWND hwnd, INT nBar,
733                                      BOOL arrows, BOOL interior )
734 {
735     HDC hdc = GetDCEx( hwnd, 0,
736                            DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW) );
737     if (!hdc) return;
738
739     SCROLL_DrawScrollBar( hwnd, hdc, nBar, arrows, interior );
740     ReleaseDC( hwnd, hdc );
741 }
742
743
744 /***********************************************************************
745  *           SCROLL_HandleKbdEvent
746  *
747  * Handle a keyboard event (only for SB_CTL scrollbars with focus).
748  */
749 static void SCROLL_HandleKbdEvent(
750 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
751 WPARAM wParam /* [in] Variable input including enable state */,
752 LPARAM lParam /* [in] Variable input including input point */)
753 {
754     TRACE("hwnd=%p wParam=%d lParam=%ld\n", hwnd, wParam, lParam);
755
756     /* hide caret on first KEYDOWN to prevent flicker */
757     if ((lParam & PFD_DOUBLEBUFFER_DONTCARE) == 0)
758         HideCaret(hwnd);
759
760     switch(wParam)
761     {
762     case VK_PRIOR: wParam = SB_PAGEUP; break;
763     case VK_NEXT:  wParam = SB_PAGEDOWN; break;
764     case VK_HOME:  wParam = SB_TOP; break;
765     case VK_END:   wParam = SB_BOTTOM; break;
766     case VK_UP:    wParam = SB_LINEUP; break;
767     case VK_DOWN:  wParam = SB_LINEDOWN; break;
768     default: return;
769     }
770     SendMessageW(GetParent(hwnd),
771         ((GetWindowLongW( hwnd, GWL_STYLE ) & SBS_VERT) ?
772             WM_VSCROLL : WM_HSCROLL), wParam, (LPARAM)hwnd);
773 }
774
775
776 /***********************************************************************
777  *           SCROLL_HandleScrollEvent
778  *
779  * Handle a mouse or timer event for the scrollbar.
780  * 'pt' is the location of the mouse event in client (for SB_CTL) or
781  * windows coordinates.
782  */
783 static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
784 {
785       /* Previous mouse position for timer events */
786     static POINT prevPt;
787       /* Thumb position when tracking started. */
788     static UINT trackThumbPos;
789       /* Position in the scroll-bar of the last button-down event. */
790     static INT lastClickPos;
791       /* Position in the scroll-bar of the last mouse event. */
792     static INT lastMousePos;
793
794     enum SCROLL_HITTEST hittest;
795     HWND hwndOwner, hwndCtl;
796     BOOL vertical;
797     INT arrowSize, thumbSize, thumbPos;
798     RECT rect;
799     HDC hdc;
800
801     SCROLLBAR_INFO *infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar );
802     if (!infoPtr) return;
803     if ((SCROLL_trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
804                   return;
805
806     if (nBar == SB_CTL && (GetWindowLongW( hwnd, GWL_STYLE ) & (SBS_SIZEGRIP | SBS_SIZEBOX)))
807     {
808         switch(msg)
809         {
810             case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
811                 HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
812                 SetCapture( hwnd );
813                 prevPt = pt;
814                 SCROLL_trackHitTest  = hittest = SCROLL_THUMB;
815                 break;
816             case WM_MOUSEMOVE:
817                 GetClientRect(GetParent(GetParent(hwnd)),&rect);
818                 prevPt = pt;
819                 break;
820             case WM_LBUTTONUP:
821                 ReleaseCapture();
822                 SCROLL_trackHitTest  = hittest = SCROLL_NOWHERE;
823                 if (hwnd==GetFocus()) ShowCaret(hwnd);
824                 break;
825             case WM_SYSTIMER:
826                 pt = prevPt;
827                 break;
828         }
829         return;
830     }
831
832     hdc = GetDCEx( hwnd, 0, DCX_CACHE | ((nBar == SB_CTL) ? 0 : DCX_WINDOW));
833     vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
834                                         &arrowSize, &thumbSize, &thumbPos );
835     hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
836     hwndCtl   = (nBar == SB_CTL) ? hwnd : 0;
837
838     switch(msg)
839     {
840       case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
841           HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
842           SCROLL_trackVertical = vertical;
843           SCROLL_trackHitTest  = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
844           lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
845           lastMousePos  = lastClickPos;
846           trackThumbPos = thumbPos;
847           prevPt = pt;
848           if (nBar == SB_CTL && (GetWindowLongW(hwnd, GWL_STYLE) & WS_TABSTOP)) SetFocus( hwnd );
849           SetCapture( hwnd );
850           break;
851
852       case WM_MOUSEMOVE:
853           hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
854           prevPt = pt;
855           break;
856
857       case WM_LBUTTONUP:
858           hittest = SCROLL_NOWHERE;
859           ReleaseCapture();
860           /* if scrollbar has focus, show back caret */
861           if (hwnd==GetFocus()) ShowCaret(hwnd);
862           break;
863
864       case WM_SYSTIMER:
865           pt = prevPt;
866           hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
867           break;
868
869       default:
870           return;  /* Should never happen */
871     }
872
873     TRACE("Event: hwnd=%p bar=%d msg=%s pt=%ld,%ld hit=%d\n",
874           hwnd, nBar, SPY_GetMsgName(msg,hwnd), pt.x, pt.y, hittest );
875
876     switch(SCROLL_trackHitTest)
877     {
878     case SCROLL_NOWHERE:  /* No tracking in progress */
879         break;
880
881     case SCROLL_TOP_ARROW:
882         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
883                            (hittest == SCROLL_trackHitTest), FALSE );
884         if (hittest == SCROLL_trackHitTest)
885         {
886             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
887             {
888                 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
889                                 SB_LINEUP, (LPARAM)hwndCtl );
890             }
891
892             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
893                             SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
894                             (TIMERPROC)0 );
895         }
896         else KillSystemTimer( hwnd, SCROLL_TIMER );
897         break;
898
899     case SCROLL_TOP_RECT:
900         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
901                              thumbPos, infoPtr->flags, vertical,
902                              (hittest == SCROLL_trackHitTest), FALSE );
903         if (hittest == SCROLL_trackHitTest)
904         {
905             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
906             {
907                 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
908                                 SB_PAGEUP, (LPARAM)hwndCtl );
909             }
910             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
911                               SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
912                               (TIMERPROC)0 );
913         }
914         else KillSystemTimer( hwnd, SCROLL_TIMER );
915         break;
916
917     case SCROLL_THUMB:
918         if (msg == WM_LBUTTONDOWN)
919         {
920             SCROLL_TrackingWin = hwnd;
921             SCROLL_TrackingBar = nBar;
922             SCROLL_TrackingPos = trackThumbPos + lastMousePos - lastClickPos;
923             SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
924                                                         vertical,
925                                                         SCROLL_TrackingPos );
926             if (!SCROLL_MovingThumb)
927                 SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
928         }
929         else if (msg == WM_LBUTTONUP)
930         {
931             if (SCROLL_MovingThumb)
932                 SCROLL_DrawMovingThumb(hdc, &rect, vertical, arrowSize, thumbSize);
933             SCROLL_TrackingWin = 0;
934             SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
935                                  thumbPos, infoPtr->flags, vertical,
936                                  FALSE, FALSE );
937         }
938         else  /* WM_MOUSEMOVE */
939         {
940             UINT pos;
941
942             if (!SCROLL_PtInRectEx( &rect, pt, vertical )) pos = lastClickPos;
943             else
944             {
945                 pt = SCROLL_ClipPos( &rect, pt );
946                 pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
947             }
948             if ( (pos != lastMousePos) || (!SCROLL_MovingThumb) )
949             {
950                 if (SCROLL_MovingThumb)
951                     SCROLL_DrawMovingThumb( hdc, &rect, vertical,
952                                         arrowSize, thumbSize );
953                 lastMousePos = pos;
954                 SCROLL_TrackingPos = trackThumbPos + pos - lastClickPos;
955                 SCROLL_TrackingVal = SCROLL_GetThumbVal( infoPtr, &rect,
956                                                          vertical,
957                                                          SCROLL_TrackingPos );
958                 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
959                                 MAKEWPARAM( SB_THUMBTRACK, SCROLL_TrackingVal),
960                                 (LPARAM)hwndCtl );
961                 if (!SCROLL_MovingThumb)
962                     SCROLL_DrawMovingThumb( hdc, &rect, vertical,
963                                         arrowSize, thumbSize );
964             }
965         }
966         break;
967
968     case SCROLL_BOTTOM_RECT:
969         SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbSize,
970                              thumbPos, infoPtr->flags, vertical,
971                              FALSE, (hittest == SCROLL_trackHitTest) );
972         if (hittest == SCROLL_trackHitTest)
973         {
974             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
975             {
976                 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
977                                 SB_PAGEDOWN, (LPARAM)hwndCtl );
978             }
979             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
980                               SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
981                               (TIMERPROC)0 );
982         }
983         else KillSystemTimer( hwnd, SCROLL_TIMER );
984         break;
985
986     case SCROLL_BOTTOM_ARROW:
987         SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
988                            FALSE, (hittest == SCROLL_trackHitTest) );
989         if (hittest == SCROLL_trackHitTest)
990         {
991             if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
992             {
993                 SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
994                                 SB_LINEDOWN, (LPARAM)hwndCtl );
995             }
996
997             SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
998                             SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
999                             (TIMERPROC)0 );
1000         }
1001         else KillSystemTimer( hwnd, SCROLL_TIMER );
1002         break;
1003     }
1004
1005     if (msg == WM_LBUTTONDOWN)
1006     {
1007
1008         if (hittest == SCROLL_THUMB)
1009         {
1010             UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
1011                                  trackThumbPos + lastMousePos - lastClickPos );
1012             SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1013                             MAKEWPARAM( SB_THUMBTRACK, val ), (LPARAM)hwndCtl );
1014         }
1015     }
1016
1017     if (msg == WM_LBUTTONUP)
1018     {
1019         hittest = SCROLL_trackHitTest;
1020         SCROLL_trackHitTest = SCROLL_NOWHERE;  /* Terminate tracking */
1021
1022         if (hittest == SCROLL_THUMB)
1023         {
1024             UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
1025                                  trackThumbPos + lastMousePos - lastClickPos );
1026             SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1027                             MAKEWPARAM( SB_THUMBPOSITION, val ), (LPARAM)hwndCtl );
1028         }
1029         SendMessageW( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
1030                           SB_ENDSCROLL, (LPARAM)hwndCtl );
1031     }
1032
1033     ReleaseDC( hwnd, hdc );
1034 }
1035
1036
1037 /***********************************************************************
1038  *           SCROLL_TrackScrollBar
1039  *
1040  * Track a mouse button press on a scroll-bar.
1041  * pt is in screen-coordinates for non-client scroll bars.
1042  */
1043 void SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
1044 {
1045     MSG msg;
1046     INT xoffset = 0, yoffset = 0;
1047
1048     if (scrollbar != SB_CTL)
1049     {
1050         WND *wndPtr = WIN_GetPtr( hwnd );
1051         if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
1052         xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
1053         yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
1054         WIN_ReleasePtr( wndPtr );
1055         ScreenToClient( hwnd, &pt );
1056         pt.x += xoffset;
1057         pt.y += yoffset;
1058     }
1059
1060     SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt );
1061
1062     do
1063     {
1064         if (!GetMessageW( &msg, 0, 0, 0 )) break;
1065         if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
1066         switch(msg.message)
1067         {
1068         case WM_LBUTTONUP:
1069         case WM_MOUSEMOVE:
1070         case WM_SYSTIMER:
1071             pt.x = (short)LOWORD(msg.lParam) + xoffset;
1072             pt.y = (short)HIWORD(msg.lParam) + yoffset;
1073             SCROLL_HandleScrollEvent( hwnd, scrollbar, msg.message, pt );
1074             break;
1075         default:
1076             TranslateMessage( &msg );
1077             DispatchMessageW( &msg );
1078             break;
1079         }
1080         if (!IsWindow( hwnd ))
1081         {
1082             ReleaseCapture();
1083             break;
1084         }
1085     } while (msg.message != WM_LBUTTONUP);
1086 }
1087
1088
1089 /***********************************************************************
1090  *           SCROLL_CreateScrollBar
1091  *
1092  *  Create a scroll bar
1093  */
1094 static void SCROLL_CreateScrollBar(
1095 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1096 LPCREATESTRUCTW lpCreate /* [in] The style and place of the scroll bar */)
1097 {
1098     LPSCROLLBAR_INFO info = SCROLL_GetScrollBarInfo(hwnd, SB_CTL);
1099     if (!info) return;
1100
1101     TRACE("hwnd=%p lpCreate=%p\n", hwnd, lpCreate);
1102
1103     if (lpCreate->style & WS_DISABLED)
1104     {
1105         info->flags = ESB_DISABLE_BOTH;
1106         TRACE("Created WS_DISABLED scrollbar\n");
1107     }
1108
1109
1110     if (lpCreate->style & (SBS_SIZEGRIP | SBS_SIZEBOX))
1111     {
1112         if (lpCreate->style & SBS_SIZEBOXTOPLEFTALIGN)
1113             MoveWindow( hwnd, lpCreate->x, lpCreate->y, GetSystemMetrics(SM_CXVSCROLL)+1,
1114                         GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1115         else if(lpCreate->style & SBS_SIZEBOXBOTTOMRIGHTALIGN)
1116             MoveWindow( hwnd, lpCreate->x+lpCreate->cx-GetSystemMetrics(SM_CXVSCROLL)-1, 
1117                         lpCreate->y+lpCreate->cy-GetSystemMetrics(SM_CYHSCROLL)-1,
1118                         GetSystemMetrics(SM_CXVSCROLL)+1,
1119                         GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1120     }
1121     else if (lpCreate->style & SBS_VERT)
1122     {
1123         if (lpCreate->style & SBS_LEFTALIGN)
1124             MoveWindow( hwnd, lpCreate->x, lpCreate->y,
1125                         GetSystemMetrics(SM_CXVSCROLL)+1, lpCreate->cy, FALSE );
1126         else if (lpCreate->style & SBS_RIGHTALIGN)
1127             MoveWindow( hwnd,
1128                         lpCreate->x+lpCreate->cx-GetSystemMetrics(SM_CXVSCROLL)-1,
1129                         lpCreate->y,
1130                         GetSystemMetrics(SM_CXVSCROLL)+1, lpCreate->cy, FALSE );
1131     }
1132     else  /* SBS_HORZ */
1133     {
1134         if (lpCreate->style & SBS_TOPALIGN)
1135             MoveWindow( hwnd, lpCreate->x, lpCreate->y,
1136                         lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1137         else if (lpCreate->style & SBS_BOTTOMALIGN)
1138             MoveWindow( hwnd,
1139                         lpCreate->x,
1140                         lpCreate->y+lpCreate->cy-GetSystemMetrics(SM_CYHSCROLL)-1,
1141                         lpCreate->cx, GetSystemMetrics(SM_CYHSCROLL)+1, FALSE );
1142     }
1143 }
1144
1145
1146 /*************************************************************************
1147  *           SCROLL_GetScrollInfo
1148  *
1149  *  Internal helper for the API function
1150  */
1151 static BOOL SCROLL_GetScrollInfo(
1152 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1153 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1154 LPSCROLLINFO info /* [in/out] (fMask specifies which values to retrieve) */)
1155 {
1156     LPSCROLLBAR_INFO infoPtr;
1157
1158     /* handle invalid data structure */
1159     if (!SCROLL_ScrollInfoValid(info)
1160         || !(infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar)))
1161             return FALSE;
1162
1163     /* fill in the desired scroll info structure */
1164     if (info->fMask & SIF_PAGE) info->nPage = infoPtr->page;
1165     if (info->fMask & SIF_POS) info->nPos = infoPtr->curVal;
1166     if ((info->fMask & SIF_TRACKPOS) && (info->cbSize == sizeof(*info)))
1167         info->nTrackPos = (SCROLL_TrackingWin == WIN_GetFullHandle(hwnd)) ? SCROLL_TrackingVal : infoPtr->curVal;
1168     if (info->fMask & SIF_RANGE)
1169     {
1170         info->nMin = infoPtr->minVal;
1171         info->nMax = infoPtr->maxVal;
1172     }
1173
1174     return (info->fMask & SIF_ALL) != 0;
1175 }
1176
1177
1178 /*************************************************************************
1179  *           SCROLL_GetScrollPos
1180  *
1181  *  Internal helper for the API function
1182  */
1183 static INT SCROLL_GetScrollPos(
1184 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1185 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */)
1186 {
1187     LPSCROLLBAR_INFO infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar);
1188     return infoPtr ? infoPtr->curVal: 0;
1189 }
1190
1191
1192 /*************************************************************************
1193  *           SCROLL_GetScrollRange
1194  *
1195  *  Internal helper for the API function
1196  *
1197  * RETURNS STD
1198  */
1199 static BOOL SCROLL_GetScrollRange(
1200 HWND hwnd, /* [in] Handle of window */
1201 INT nBar, /* [in] One of SB_HORZ, SB_VERT, or SB_CTL  */
1202 LPINT lpMin, /* [out] Where to store minimum value */
1203 LPINT lpMax /* [out] Where to store maximum value */)
1204 {
1205     LPSCROLLBAR_INFO infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar);
1206
1207     if (lpMin) *lpMin = infoPtr ? infoPtr->minVal : 0;
1208     if (lpMax) *lpMax = infoPtr ? infoPtr->maxVal : 0;
1209
1210     return TRUE;
1211 }
1212
1213
1214 /*************************************************************************
1215  *           SCROLL_SetScrollRange
1216  *
1217  */
1218 static BOOL SCROLL_SetScrollRange(
1219         HWND hwnd, /* [in] Handle of window */
1220         INT nBar, /* [in] One of SB_HORZ, SB_VERT, or SB_CTL  */
1221         INT minVal, /* [out] minimum value */
1222         INT maxVal /* [out] maximum value */)
1223 {
1224     LPSCROLLBAR_INFO infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar);
1225
1226     TRACE("hwnd=%p nBar=%d min=%d max=%d\n", hwnd, nBar, minVal, maxVal);
1227
1228     if (infoPtr)
1229     {
1230         infoPtr->minVal = minVal;
1231         infoPtr->maxVal = maxVal;
1232     }
1233     return TRUE;
1234 }
1235
1236
1237 /***********************************************************************
1238  *           ScrollBarWndProc
1239  */
1240 static LRESULT WINAPI ScrollBarWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1241 {
1242     if (!IsWindow( hwnd )) return 0;
1243
1244     switch(message)
1245     {
1246     case WM_CREATE:
1247         SCROLL_CreateScrollBar(hwnd, (LPCREATESTRUCTW)lParam);
1248         break;
1249
1250     case WM_ENABLE:
1251         {
1252             SCROLLBAR_INFO *infoPtr;
1253             if ((infoPtr = SCROLL_GetScrollBarInfo( hwnd, SB_CTL )))
1254             {
1255                 infoPtr->flags = wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
1256                 SCROLL_RefreshScrollBar(hwnd, SB_CTL, TRUE, TRUE);
1257             }
1258         }
1259         return 0;
1260
1261     case WM_LBUTTONDBLCLK:
1262     case WM_LBUTTONDOWN:
1263         {
1264             POINT pt;
1265             pt.x = (short)LOWORD(lParam);
1266             pt.y = (short)HIWORD(lParam);
1267             SCROLL_TrackScrollBar( hwnd, SB_CTL, pt );
1268         }
1269         break;
1270     case WM_LBUTTONUP:
1271     case WM_MOUSEMOVE:
1272     case WM_SYSTIMER:
1273         {
1274             POINT pt;
1275             pt.x = (short)LOWORD(lParam);
1276             pt.y = (short)HIWORD(lParam);
1277             SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, pt );
1278         }
1279         break;
1280
1281     case WM_KEYDOWN:
1282         SCROLL_HandleKbdEvent(hwnd, wParam, lParam);
1283         break;
1284
1285     case WM_KEYUP:
1286         ShowCaret(hwnd);
1287         break;
1288
1289     case WM_SETFOCUS:
1290         {
1291             /* Create a caret when a ScrollBar get focus */
1292             RECT rect;
1293             int arrowSize, thumbSize, thumbPos, vertical;
1294             vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,
1295                                                 &arrowSize, &thumbSize, &thumbPos );
1296             if (!vertical)
1297             {
1298                 CreateCaret(hwnd, (HBITMAP)1, thumbSize-2, rect.bottom-rect.top-2);
1299                 SetCaretPos(thumbPos+1, rect.top+1);
1300             }
1301             else
1302             {
1303                 CreateCaret(hwnd, (HBITMAP)1, rect.right-rect.left-2,thumbSize-2);
1304                 SetCaretPos(rect.top+1, thumbPos+1);
1305             }
1306             ShowCaret(hwnd);
1307         }
1308         break;
1309
1310     case WM_KILLFOCUS:
1311         {
1312             RECT rect;
1313             int arrowSize, thumbSize, thumbPos, vertical;
1314             vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,&arrowSize, &thumbSize, &thumbPos );
1315             if (!vertical){
1316                 rect.left=thumbPos+1;
1317                 rect.right=rect.left+thumbSize;
1318             }
1319             else
1320             {
1321                 rect.top=thumbPos+1;
1322                 rect.bottom=rect.top+thumbSize;
1323             }
1324             HideCaret(hwnd);
1325             InvalidateRect(hwnd,&rect,0);
1326             DestroyCaret();
1327         }
1328         break;
1329
1330     case WM_ERASEBKGND:
1331          return 1;
1332
1333     case WM_GETDLGCODE:
1334          return DLGC_WANTARROWS; /* Windows returns this value */
1335
1336     case WM_PAINT:
1337         {
1338             PAINTSTRUCT ps;
1339             HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
1340             if (GetWindowLongW( hwnd, GWL_STYLE ) & SBS_SIZEGRIP)
1341             {
1342                 SCROLL_DrawSizeGrip( hwnd, hdc);
1343             }
1344             else if (GetWindowLongW( hwnd, GWL_STYLE ) & SBS_SIZEBOX)
1345             {
1346                 RECT rc;
1347                 GetClientRect( hwnd, &rc );
1348                 FillRect( hdc, &rc, GetSysColorBrush(COLOR_SCROLLBAR) );
1349             }
1350             else
1351                 SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL, TRUE, TRUE );
1352             if (!wParam) EndPaint(hwnd, &ps);
1353         }
1354         break;
1355
1356     case SBM_SETPOS16:
1357     case SBM_SETPOS:
1358         return SetScrollPos( hwnd, SB_CTL, wParam, (BOOL)lParam );
1359
1360     case SBM_GETPOS16:
1361     case SBM_GETPOS:
1362        return SCROLL_GetScrollPos(hwnd, SB_CTL);
1363
1364     case SBM_SETRANGE16:
1365         if (wParam) message = SBM_SETRANGEREDRAW;
1366         wParam = LOWORD(lParam);
1367         lParam = HIWORD(lParam);
1368         /* fall through */
1369     case SBM_SETRANGEREDRAW:
1370     case SBM_SETRANGE:
1371         {
1372             INT oldPos = SCROLL_GetScrollPos( hwnd, SB_CTL );
1373             SCROLL_SetScrollRange( hwnd, SB_CTL, wParam, lParam );
1374             if (message == SBM_SETRANGEREDRAW)
1375                 SCROLL_RefreshScrollBar( hwnd, SB_CTL, TRUE, TRUE );
1376             if (oldPos != SCROLL_GetScrollPos( hwnd, SB_CTL )) return oldPos;
1377         }
1378         return 0;
1379
1380     case SBM_GETRANGE16:
1381     {
1382         INT min, max;
1383
1384         SCROLL_GetScrollRange(hwnd, SB_CTL, &min, &max);
1385         return MAKELRESULT(min, max);
1386     }
1387
1388     case SBM_GETRANGE:
1389         return SCROLL_GetScrollRange(hwnd, SB_CTL, (LPINT)wParam, (LPINT)lParam);
1390
1391     case SBM_ENABLE_ARROWS16:
1392     case SBM_ENABLE_ARROWS:
1393         return EnableScrollBar( hwnd, SB_CTL, wParam );
1394
1395     case SBM_SETSCROLLINFO:
1396         return SCROLL_SetScrollInfo( hwnd, SB_CTL, (SCROLLINFO *)lParam, wParam );
1397
1398     case SBM_GETSCROLLINFO:
1399         return SCROLL_GetScrollInfo(hwnd, SB_CTL, (SCROLLINFO *)lParam);
1400
1401     case 0x00e5:
1402     case 0x00e7:
1403     case 0x00e8:
1404     case 0x00eb:
1405     case 0x00ec:
1406     case 0x00ed:
1407     case 0x00ee:
1408     case 0x00ef:
1409         ERR("unknown Win32 msg %04x wp=%08x lp=%08lx\n",
1410                     message, wParam, lParam );
1411         break;
1412
1413     default:
1414         if (message >= WM_USER)
1415             WARN("unknown msg %04x wp=%04x lp=%08lx\n",
1416                          message, wParam, lParam );
1417         return DefWindowProcW( hwnd, message, wParam, lParam );
1418     }
1419     return 0;
1420 }
1421
1422
1423 /*************************************************************************
1424  *           SetScrollInfo   (USER32.@)
1425  * SetScrollInfo can be used to set the position, upper bound,
1426  * lower bound, and page size of a scrollbar control.
1427  *
1428  * RETURNS
1429  *    Scrollbar position
1430  *
1431  * NOTE
1432  *    For 100 lines of text to be displayed in a window of 25 lines,
1433  *  one would for instance use info->nMin=0, info->nMax=75
1434  *  (corresponding to the 76 different positions of the window on
1435  *  the text), and info->nPage=25.
1436  */
1437 INT WINAPI SetScrollInfo(
1438 HWND hwnd /* [in] Handle of window whose scrollbar will be affected */,
1439 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1440 const SCROLLINFO *info /* [in] Specifies what to change and new values */,
1441 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */)
1442 {
1443     TRACE("hwnd=%p nBar=%d info=%p, bRedraw=%d\n", hwnd, nBar, info, bRedraw);
1444
1445     /* Refer SB_CTL requests to the window */
1446     if (nBar == SB_CTL)
1447         return SendMessageW(hwnd, SBM_SETSCROLLINFO, bRedraw, (LPARAM)info);
1448     else
1449         return SCROLL_SetScrollInfo( hwnd, nBar, info, bRedraw );
1450 }
1451
1452 static INT SCROLL_SetScrollInfo( HWND hwnd, INT nBar, const SCROLLINFO *info, BOOL bRedraw )
1453 {
1454     /* Update the scrollbar state and set action flags according to
1455      * what has to be done graphics wise. */
1456
1457     SCROLLBAR_INFO *infoPtr;
1458     UINT new_flags;
1459     BOOL bChangeParams = FALSE; /* don't show/hide scrollbar if params don't change */
1460     INT action = 0;
1461
1462     if (!(infoPtr = SCROLL_GetScrollBarInfo(hwnd, nBar))) return 0;
1463     if (info->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL)) return 0;
1464     if ((info->cbSize != sizeof(*info)) &&
1465         (info->cbSize != sizeof(*info)-sizeof(info->nTrackPos))) return 0;
1466
1467     if (TRACE_ON(scroll))
1468     {
1469         TRACE("hwnd=%p bar=%d", hwnd, nBar);
1470         if (info->fMask & SIF_PAGE) TRACE( " page=%d", info->nPage );
1471         if (info->fMask & SIF_POS) TRACE( " pos=%d", info->nPos );
1472         if (info->fMask & SIF_RANGE) TRACE( " min=%d max=%d", info->nMin, info->nMax );
1473         TRACE("\n");
1474     }
1475
1476     /* Set the page size */
1477
1478     if (info->fMask & SIF_PAGE)
1479     {
1480         if( infoPtr->page != info->nPage )
1481         {
1482             infoPtr->page = info->nPage;
1483             action |= SA_SSI_REFRESH;
1484            bChangeParams = TRUE;
1485         }
1486     }
1487
1488     /* Set the scroll pos */
1489
1490     if (info->fMask & SIF_POS)
1491     {
1492         if( infoPtr->curVal != info->nPos )
1493         {
1494             infoPtr->curVal = info->nPos;
1495             action |= SA_SSI_REFRESH;
1496         }
1497     }
1498
1499     /* Set the scroll range */
1500
1501     if (info->fMask & SIF_RANGE)
1502     {
1503         /* Invalid range -> range is set to (0,0) */
1504         if ((info->nMin > info->nMax) ||
1505             ((UINT)(info->nMax - info->nMin) >= 0x80000000))
1506         {
1507             infoPtr->minVal = 0;
1508             infoPtr->maxVal = 0;
1509             bChangeParams = TRUE;
1510         }
1511         else
1512         {
1513             if( infoPtr->minVal != info->nMin ||
1514                 infoPtr->maxVal != info->nMax )
1515             {
1516                 action |= SA_SSI_REFRESH;
1517                 infoPtr->minVal = info->nMin;
1518                 infoPtr->maxVal = info->nMax;
1519                 bChangeParams = TRUE;
1520             }
1521         }
1522     }
1523
1524     /* Make sure the page size is valid */
1525
1526     if (infoPtr->page < 0) infoPtr->page = 0;
1527     else if (infoPtr->page > infoPtr->maxVal - infoPtr->minVal + 1 )
1528         infoPtr->page = infoPtr->maxVal - infoPtr->minVal + 1;
1529
1530     /* Make sure the pos is inside the range */
1531
1532     if (infoPtr->curVal < infoPtr->minVal)
1533         infoPtr->curVal = infoPtr->minVal;
1534     else if (infoPtr->curVal > infoPtr->maxVal - max( infoPtr->page-1, 0 ))
1535         infoPtr->curVal = infoPtr->maxVal - max( infoPtr->page-1, 0 );
1536
1537     TRACE("    new values: page=%d pos=%d min=%d max=%d\n",
1538                  infoPtr->page, infoPtr->curVal,
1539                  infoPtr->minVal, infoPtr->maxVal );
1540
1541     /* don't change the scrollbar state if SetScrollInfo
1542      * is just called with SIF_DISABLENOSCROLL
1543      */
1544     if(!(info->fMask & SIF_ALL)) goto done;
1545
1546     /* Check if the scrollbar should be hidden or disabled */
1547
1548     if (info->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL))
1549     {
1550         new_flags = infoPtr->flags;
1551         if (infoPtr->minVal >= infoPtr->maxVal - max( infoPtr->page-1, 0 ))
1552         {
1553             /* Hide or disable scroll-bar */
1554             if (info->fMask & SIF_DISABLENOSCROLL)
1555             {
1556                 new_flags = ESB_DISABLE_BOTH;
1557                 action |= SA_SSI_REFRESH;
1558             }
1559             else if ((nBar != SB_CTL) && bChangeParams)
1560             {
1561                 action = SA_SSI_HIDE;
1562                 goto done;
1563             }
1564         }
1565         else  /* Show and enable scroll-bar */
1566         {
1567             new_flags = 0;
1568             if ((nBar != SB_CTL) && bChangeParams)
1569                 action |= SA_SSI_SHOW;
1570         }
1571
1572         if (infoPtr->flags != new_flags) /* check arrow flags */
1573         {
1574             infoPtr->flags = new_flags;
1575             action |= SA_SSI_REPAINT_ARROWS;
1576         }
1577     }
1578
1579 done:
1580     if( action & SA_SSI_HIDE )
1581         SCROLL_ShowScrollBar( hwnd, nBar, FALSE, FALSE );
1582     else
1583     {
1584         if( action & SA_SSI_SHOW )
1585             if( SCROLL_ShowScrollBar( hwnd, nBar, TRUE, TRUE ) )
1586                 return infoPtr->curVal; /* SetWindowPos() already did the painting */
1587
1588         if( bRedraw )
1589             SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1590         else if( action & SA_SSI_REPAINT_ARROWS )
1591             SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, FALSE );
1592     }
1593
1594     /* Return current position */
1595     return infoPtr->curVal;
1596 }
1597
1598
1599 /*************************************************************************
1600  *           GetScrollInfo   (USER32.@)
1601  *
1602  * GetScrollInfo can be used to retrieve the position, upper bound,
1603  * lower bound, and page size of a scrollbar control.
1604  *
1605  * RETURNS STD
1606  */
1607 BOOL WINAPI GetScrollInfo(
1608 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1609 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1610 LPSCROLLINFO info /* [in/out] (fMask specifies which values to retrieve) */)
1611 {
1612     TRACE("hwnd=%p nBar=%d info=%p\n", hwnd, nBar, info);
1613
1614     /* Refer SB_CTL requests to the window */
1615     if (nBar == SB_CTL)
1616         SendMessageW(hwnd, SBM_GETSCROLLINFO, (WPARAM)0, (LPARAM)info);
1617     else
1618         SCROLL_GetScrollInfo(hwnd, nBar, info);
1619
1620     return TRUE;
1621 }
1622
1623
1624 /*************************************************************************
1625  *           SetScrollPos   (USER32.@)
1626  *
1627  * RETURNS
1628  *    Success: Scrollbar position
1629  *    Failure: 0
1630  *
1631  * REMARKS
1632  *    Note the ambiguity when 0 is returned.  Use GetLastError
1633  *    to make sure there was an error (and to know which one).
1634  */
1635 INT WINAPI SetScrollPos(
1636 HWND hwnd /* [in] Handle of window whose scrollbar will be affected */,
1637 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */,
1638 INT nPos /* [in] New value */,
1639 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */ )
1640 {
1641     SCROLLINFO info;
1642     SCROLLBAR_INFO *infoPtr;
1643     INT oldPos;
1644
1645     if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar ))) return 0;
1646     oldPos      = infoPtr->curVal;
1647     info.cbSize = sizeof(info);
1648     info.nPos   = nPos;
1649     info.fMask  = SIF_POS;
1650     SetScrollInfo( hwnd, nBar, &info, bRedraw );
1651     return oldPos;
1652 }
1653
1654
1655 /*************************************************************************
1656  *           GetScrollPos   (USER32.@)
1657  *
1658  * RETURNS
1659  *    Success: Current position
1660  *    Failure: 0
1661  *
1662  * REMARKS
1663  *    There is ambiguity when 0 is returned.  Use GetLastError
1664  *    to make sure there was an error (and to know which one).
1665  */
1666 INT WINAPI GetScrollPos(
1667 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1668 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */)
1669 {
1670     TRACE("hwnd=%p nBar=%d\n", hwnd, nBar);
1671
1672     /* Refer SB_CTL requests to the window */
1673     if (nBar == SB_CTL)
1674         return SendMessageW(hwnd, SBM_GETPOS, (WPARAM)0, (LPARAM)0);
1675     else
1676         return SCROLL_GetScrollPos(hwnd, nBar);
1677 }
1678
1679
1680 /*************************************************************************
1681  *           SetScrollRange   (USER32.@)
1682  *
1683  * RETURNS STD
1684  */
1685 BOOL WINAPI SetScrollRange(
1686 HWND hwnd, /* [in] Handle of window whose scrollbar will be affected */
1687 INT nBar, /* [in] One of SB_HORZ, SB_VERT, or SB_CTL */
1688 INT minVal, /* [in] New minimum value */
1689 INT maxVal, /* [in] New maximum value */
1690 BOOL bRedraw /* [in] Should scrollbar be redrawn afterwards ? */)
1691 {
1692     SCROLLINFO info;
1693  
1694     TRACE("hwnd=%p nBar=%d min=%d max=%d, bRedraw=%d\n", hwnd, nBar, minVal, maxVal, bRedraw);
1695  
1696     info.cbSize = sizeof(info);
1697     info.fMask  = SIF_RANGE;
1698     info.nMin   = minVal;
1699     info.nMax   = maxVal;
1700     SetScrollInfo( hwnd, nBar, &info, bRedraw );
1701     return TRUE;
1702 }
1703
1704
1705 /*************************************************************************
1706  *           SCROLL_SetNCSbState
1707  *
1708  * Updates both scrollbars at the same time. Used by MDI CalcChildScroll().
1709  */
1710 INT SCROLL_SetNCSbState(HWND hwnd, int vMin, int vMax, int vPos,
1711                         int hMin, int hMax, int hPos)
1712 {
1713     SCROLLINFO vInfo, hInfo;
1714
1715     vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
1716     vInfo.nMin   = vMin;
1717     vInfo.nMax   = vMax;
1718     vInfo.nPos   = vPos;
1719     hInfo.nMin   = hMin;
1720     hInfo.nMax   = hMax;
1721     hInfo.nPos   = hPos;
1722     vInfo.fMask  = hInfo.fMask = SIF_RANGE | SIF_POS;
1723
1724     SCROLL_SetScrollInfo( hwnd, SB_VERT, &vInfo, TRUE );
1725     SCROLL_SetScrollInfo( hwnd, SB_HORZ, &hInfo, TRUE );
1726
1727     return 0;
1728 }
1729
1730
1731 /*************************************************************************
1732  *           GetScrollRange   (USER32.@)
1733  *
1734  * RETURNS STD
1735  */
1736 BOOL WINAPI GetScrollRange(
1737 HWND hwnd /* [in] Handle of window with scrollbar(s) */,
1738 INT nBar /* [in] One of SB_HORZ, SB_VERT, or SB_CTL  */,
1739 LPINT lpMin /* [out] Where to store minimum value */,
1740 LPINT lpMax /* [out] Where to store maximum value */)
1741 {
1742     TRACE("hwnd=%p nBar=%d lpMin=%p lpMax=%p\n", hwnd, nBar, lpMin, lpMax);
1743
1744     /* Refer SB_CTL requests to the window */
1745     if (nBar == SB_CTL)
1746         SendMessageW(hwnd, SBM_GETRANGE, (WPARAM)lpMin, (LPARAM)lpMax);
1747     else
1748         SCROLL_GetScrollRange(hwnd, nBar, lpMin, lpMax);
1749
1750     return TRUE;
1751 }
1752
1753
1754 /*************************************************************************
1755  *           SCROLL_ShowScrollBar()
1756  *
1757  * Back-end for ShowScrollBar(). Returns FALSE if no action was taken.
1758  */
1759 BOOL SCROLL_ShowScrollBar( HWND hwnd, INT nBar,
1760                              BOOL fShowH, BOOL fShowV )
1761 {
1762     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1763
1764     TRACE("hwnd=%p bar=%d horz=%d, vert=%d\n", hwnd, nBar, fShowH, fShowV );
1765
1766     switch(nBar)
1767     {
1768     case SB_CTL:
1769         ShowWindow( hwnd, fShowH ? SW_SHOW : SW_HIDE );
1770         return TRUE;
1771
1772     case SB_BOTH:
1773     case SB_HORZ:
1774         if (fShowH)
1775         {
1776             fShowH = !(style & WS_HSCROLL);
1777             style |= WS_HSCROLL;
1778         }
1779         else  /* hide it */
1780         {
1781             fShowH = (style & WS_HSCROLL);
1782             style &= ~WS_HSCROLL;
1783         }
1784         if( nBar == SB_HORZ ) {
1785             fShowV = FALSE;
1786             break;
1787         }
1788         /* fall through */
1789
1790     case SB_VERT:
1791         if (fShowV)
1792         {
1793             fShowV = !(style & WS_VSCROLL);
1794             style |= WS_VSCROLL;
1795         }
1796         else  /* hide it */
1797         {
1798             fShowV = (style & WS_VSCROLL);
1799             style &= ~WS_VSCROLL;
1800         }
1801         if ( nBar == SB_VERT )
1802            fShowH = FALSE;
1803         break;
1804
1805     default:
1806         return FALSE;  /* Nothing to do! */
1807     }
1808
1809     if( fShowH || fShowV ) /* frame has been changed, let the window redraw itself */
1810     {
1811         WIN_SetStyle( hwnd, style );
1812         SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
1813                     | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1814         return TRUE;
1815     }
1816     return FALSE; /* no frame changes */
1817 }
1818
1819
1820 /*************************************************************************
1821  *           ShowScrollBar   (USER32.@)
1822  *
1823  * RETURNS STD
1824  */
1825 BOOL WINAPI ShowScrollBar(
1826 HWND hwnd, /* [in] Handle of window whose scrollbar(s) will be affected   */
1827 INT nBar, /* [in] One of SB_HORZ, SB_VERT, SB_BOTH or SB_CTL */
1828 BOOL fShow /* [in] TRUE = show, FALSE = hide  */)
1829 {
1830     SCROLL_ShowScrollBar( hwnd, nBar, (nBar == SB_VERT) ? 0 : fShow,
1831                                       (nBar == SB_HORZ) ? 0 : fShow );
1832     return TRUE;
1833 }
1834
1835
1836 /*************************************************************************
1837  *           EnableScrollBar   (USER32.@)
1838  */
1839 BOOL WINAPI EnableScrollBar( HWND hwnd, INT nBar, UINT flags )
1840 {
1841     BOOL bFineWithMe;
1842     SCROLLBAR_INFO *infoPtr;
1843
1844     TRACE("%p %d %d\n", hwnd, nBar, flags );
1845
1846     flags &= ESB_DISABLE_BOTH;
1847
1848     if (nBar == SB_BOTH)
1849     {
1850         if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, SB_VERT ))) return FALSE;
1851         if (!(bFineWithMe = (infoPtr->flags == flags)) )
1852         {
1853             infoPtr->flags = flags;
1854             SCROLL_RefreshScrollBar( hwnd, SB_VERT, TRUE, TRUE );
1855         }
1856         nBar = SB_HORZ;
1857     }
1858     else
1859         bFineWithMe = TRUE;
1860
1861     if (!(infoPtr = SCROLL_GetScrollBarInfo( hwnd, nBar ))) return FALSE;
1862     if (bFineWithMe && infoPtr->flags == flags) return FALSE;
1863     infoPtr->flags = flags;
1864
1865     SCROLL_RefreshScrollBar( hwnd, nBar, TRUE, TRUE );
1866     return TRUE;
1867 }