3272e890d09f93302317900fd379719b667b7f84
[reactos.git] / subsys / win32k / ntuser / scrollbar.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:        See COPYING in the top level directory
22  * PROJECT:          ReactOS kernel
23  * PURPOSE:          Scrollbars
24  * FILE:             subsys/win32k/ntuser/scrollbar.c
25  * PROGRAMER:        Jason Filby (jasonfilby@yahoo.com)
26  * REVISION HISTORY:
27  *       16-11-2002  Jason Filby  Created
28  */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <win32k/win32k.h>
33 #include <include/object.h>
34 #include <include/window.h>
35 #include <include/class.h>
36 #include <include/error.h>
37 #include <include/winsta.h>
38 #include <include/winpos.h>
39 #include <include/rect.h>
40 #include <include/scroll.h>
41
42 //#define NDEBUG
43 #include <debug.h>
44
45 #define SCROLL_MIN_RECT  4               /* Minimum size of the rectangle between the arrows */
46 #define SCROLL_ARROW_THUMB_OVERLAP 0     /* Overlap between arrows and thumb */
47
48 #define SBRG_SCROLLBAR     0 /* the scrollbar itself */
49 #define SBRG_TOPRIGHTBTN   1 /* the top or right button */
50 #define SBRG_PAGEUPRIGHT   2 /* the page up or page right region */
51 #define SBRG_SCROLLBOX     3 /* the scroll box */
52 #define SBRG_PAGEDOWNLEFT  4 /* the page down or page left region */
53 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
54
55 /***********************************************************************
56  *           MulDiv  (copied from kernel32)
57  */
58 static INT IntMulDiv(
59   INT nMultiplicand,
60   INT nMultiplier,
61   INT nDivisor)
62 {
63 #if SIZEOF_LONG_LONG >= 8
64     long long ret;
65
66     if (!nDivisor) return -1;
67
68     /* We want to deal with a positive divisor to simplify the logic. */
69     if (nDivisor < 0)
70     {
71       nMultiplicand = - nMultiplicand;
72       nDivisor = -nDivisor;
73     }
74
75     /* If the result is positive, we "add" to round. else, we subtract to round. */
76     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
77          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
78       ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
79     else
80       ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
81
82     if ((ret > 2147483647) || (ret < -2147483647)) return -1;
83     return ret;
84 #else
85     if (!nDivisor) return -1;
86
87     /* We want to deal with a positive divisor to simplify the logic. */
88     if (nDivisor < 0)
89     {
90       nMultiplicand = - nMultiplicand;
91       nDivisor = -nDivisor;
92     }
93
94     /* If the result is positive, we "add" to round. else, we subtract to round. */
95     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
96          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
97       return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
98
99     return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
100
101 #endif
102 }
103
104
105 /* FUNCTIONS *****************************************************************/
106
107 /* Ported from WINE20020904 */
108 /* Compute the scroll bar rectangle, in drawing coordinates (i.e. client coords for SB_CTL, window coords for SB_VERT and
109  * SB_HORZ). 'arrowSize' returns the width or height of an arrow (depending on * the orientation of the scrollbar),
110  * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
111  * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
112  */
113 BOOL STDCALL
114 IntGetScrollBarRect (PWINDOW_OBJECT Window, INT nBar, PRECT lprect)
115 {
116   BOOL vertical;
117   RECT ClientRect = Window->ClientRect;
118   RECT WindowRect = Window->WindowRect;
119
120   switch (nBar)
121     {
122     case SB_HORZ:
123       lprect->left = ClientRect.left - WindowRect.left + 1;
124       lprect->top = ClientRect.bottom - WindowRect.top;
125       lprect->right = ClientRect.right - WindowRect.left - 1;
126       lprect->bottom = lprect->top + NtUserGetSystemMetrics (SM_CYHSCROLL);
127       if (Window->Style & WS_BORDER)
128         {
129           lprect->left--;
130           lprect->right++;
131         }
132       vertical = FALSE;
133       break;
134
135     case SB_VERT:
136       lprect->left = (ClientRect.right - WindowRect.left);
137       lprect->top = (ClientRect.top - WindowRect.top) + 1;
138       lprect->right = (lprect->left + NtUserGetSystemMetrics (SM_CXVSCROLL));
139       lprect->bottom = (ClientRect.bottom - WindowRect.top) - 1;
140       if (Window->Style & WS_BORDER)
141         {
142           lprect->top--;
143           lprect->bottom++;
144         }
145       else if (Window->Style & WS_HSCROLL)
146         lprect->bottom++;
147       vertical = TRUE;
148       break;
149
150     case SB_CTL:
151       IntGetClientRect (Window, lprect);
152       vertical = ((Window->Style & SBS_VERT) != 0);
153       break;
154
155     default:
156       IntReleaseWindowObject(Window);
157       return FALSE;
158     }
159
160   return vertical;
161 }
162
163 #define MINTRACKTHUMB (8)
164 BOOL FASTCALL
165 IntCalculateThumb(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi, LPSCROLLINFO psi)
166 {
167   INT Thumb, ThumbBox, ThumbPos, cxy, mx;
168   switch(idObject)
169   {
170     case SB_HORZ:
171       Thumb = NtUserGetSystemMetrics(SM_CXHSCROLL);
172       cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
173       break;
174     case SB_VERT:
175       Thumb = NtUserGetSystemMetrics(SM_CYVSCROLL);
176       cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
177       break;
178     case SB_CTL:
179       /* FIXME */
180       return FALSE;
181     default:
182       return FALSE;
183   }
184
185   ThumbPos = Thumb;
186   /* calculate Thumb */
187   if(cxy <= (2 * Thumb))
188   {
189     Thumb = cxy / 2;
190     psbi->xyThumbTop = 0;
191     psbi->xyThumbBottom = 0;
192     ThumbPos = Thumb;
193   }
194   else
195   {
196     ThumbBox = psi->nPage ? MINTRACKTHUMB : NtUserGetSystemMetrics(SM_CXHTHUMB);
197     cxy -= (2 * Thumb);
198     if(cxy >= ThumbBox)
199     {
200       if(psi->nPage)
201       {
202         ThumbBox = max(IntMulDiv(cxy, psi->nPage, psi->nMax - psi->nMin + 1), ThumbBox);
203       }
204       
205       if(cxy > ThumbBox)
206       {
207         mx = psi->nMax - max(psi->nPage - 1, 0);
208         if(psi->nMin < mx)
209           ThumbPos = Thumb + IntMulDiv(cxy, psi->nPos - psi->nMin, psi->nMax - psi->nMin + 1);
210       }
211       
212       psbi->xyThumbTop = ThumbPos;
213       psbi->xyThumbBottom = ThumbPos + ThumbBox;
214     }
215     else
216     {
217       psbi->xyThumbTop = 0;
218       psbi->xyThumbBottom = 0;
219     }
220   }
221   psbi->dxyLineButton = Thumb;
222
223   return TRUE;
224 }
225
226 DWORD FASTCALL 
227 IntCreateScrollBar(PWINDOW_OBJECT Window, LONG idObject)
228 {
229   PSCROLLBARINFO psbi;
230   LPSCROLLINFO psi;
231   LRESULT Result;
232   INT i;
233
234   psbi = ExAllocatePool(PagedPool, sizeof(SCROLLBARINFO) + sizeof(SCROLLINFO));
235   if(!psbi)
236     return FALSE;
237     
238   psi = (LPSCROLLINFO)((PSCROLLBARINFO)(psbi + 1));
239   
240   psi->cbSize = sizeof(LPSCROLLINFO);
241   psi->nMin = 0;
242   psi->nMax = 100;
243   psi->nPage = 0;
244   psi->nPos = 0;
245   psi->nTrackPos = 0;
246
247   Result = WinPosGetNonClientSize(Window->Self,
248                                   &Window->WindowRect,
249                                   &Window->ClientRect);
250
251   psbi->cbSize = sizeof(SCROLLBARINFO);
252
253   for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
254     psbi->rgstate[i] = 0;
255
256   switch(idObject)
257   {
258     case SB_HORZ:
259       //psbi->dxyLineButton = NtUserGetSystemMetrics(SM_CXHSCROLL);
260       Window->pHScroll = psbi;
261       break;
262     case SB_VERT:
263       //psbi->dxyLineButton = NtUserGetSystemMetrics(SM_CYVSCROLL);
264       Window->pVScroll = psbi;
265       break;
266     case SB_CTL:
267       /* FIXME - set psbi->dxyLineButton */
268       Window->wExtra = psbi;
269       break;
270     default:
271       ExFreePool(psbi);
272       return FALSE;
273   }
274
275   IntGetScrollBarRect(Window, idObject, &(psbi->rcScrollBar));
276   IntCalculateThumb(Window, idObject, psbi, psi);
277
278   return 0;
279 }
280
281 BOOL FASTCALL 
282 IntDestroyScrollBar(PWINDOW_OBJECT Window, LONG idObject)
283 {
284   switch(idObject)
285   {
286     case SB_HORZ:
287       if(Window->pHScroll)
288       {
289         ExFreePool(Window->pHScroll);
290         Window->pHScroll = NULL;
291         return TRUE;
292       }
293       return FALSE;
294     case SB_VERT:
295       if(Window->pVScroll)
296       {
297         ExFreePool(Window->pVScroll);
298         Window->pVScroll = NULL;
299         return TRUE;
300       }
301       return FALSE;
302     case SB_CTL:
303       if(Window->wExtra)
304       {
305         ExFreePool(Window->wExtra);
306         Window->wExtra = NULL;
307         return TRUE;
308       }
309       return FALSE;
310   }
311   return FALSE;
312 }
313
314 #define CHANGERGSTATE(item, status) \
315   if(Info->rgstate[(item)] != (status)) \
316     Chg = TRUE; \
317   Info->rgstate[(item)] = (status); 
318
319
320 BOOL STDCALL
321 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
322 {
323   BOOL Chg = FALSE;
324   switch(wArrows)
325   {
326     case ESB_DISABLE_BOTH:
327       CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
328       CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
329       break;
330     case ESB_DISABLE_RTDN:
331       if(Horz)
332       {
333         CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
334       }
335       else
336       {
337         CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
338       }
339       break;
340     case ESB_DISABLE_LTUP:
341       if(Horz)
342       {
343         CHANGERGSTATE(SBRG_TOPRIGHTBTN, STATE_SYSTEM_UNAVAILABLE);
344       }
345       else
346       {
347         CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, STATE_SYSTEM_UNAVAILABLE);
348       }
349       break;
350     case ESB_ENABLE_BOTH:
351       CHANGERGSTATE(SBRG_TOPRIGHTBTN, 0);
352       CHANGERGSTATE(SBRG_BOTTOMLEFTBTN, 0);
353       break;
354   }
355   return Chg;
356 }
357
358
359 BOOL
360 STDCALL
361 NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
362 {
363   PWINDOW_OBJECT Window;
364   PSCROLLBARINFO sbi;
365   LPSCROLLINFO psi;
366   INT Bar;
367   
368   if(!psbi || (psbi->cbSize != sizeof(SCROLLBARINFO)))
369   {
370     SetLastWin32Error(ERROR_INVALID_PARAMETER);
371     return FALSE;
372   }
373   
374   Window = IntGetWindowObject(hWnd);
375
376   if(!Window)
377   {
378     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
379     return FALSE;
380   }
381
382   switch(idObject)
383   {
384     case OBJID_HSCROLL:
385       if(Window->pHScroll)
386       {
387         Bar = SB_HORZ;
388         sbi = Window->pHScroll;
389         break;
390       }
391       /* fall through */
392     case OBJID_VSCROLL:
393       if(Window->pVScroll)
394       {
395         Bar = SB_VERT;
396         sbi = Window->pVScroll;
397         break;
398       }
399       /* fall through */
400     case OBJID_CLIENT:
401       if(Window->wExtra)
402       {
403         Bar = SB_CTL;
404         sbi = Window->wExtra;
405         break;
406       }
407       /* fall through */
408     default:
409       IntReleaseWindowObject(Window);
410       SetLastWin32Error(ERROR_INVALID_PARAMETER);
411       return FALSE;
412   }
413   
414   psi = (LPSCROLLINFO)((PSCROLLBARINFO)(sbi + 1));
415
416   IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
417   IntCalculateThumb(Window, Bar, sbi, psi);
418   
419   memcpy(psbi, sbi, sizeof(SCROLLBARINFO));
420
421   IntReleaseWindowObject(Window);
422   return TRUE;
423 }
424
425
426 BOOL
427 STDCALL
428 NtUserGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
429 {
430   PWINDOW_OBJECT Window;
431   LPSCROLLINFO psi;
432   UINT Mask;
433   PSCROLLBARINFO Info = NULL;
434   
435   if(!lpsi || ((lpsi->cbSize != sizeof(SCROLLINFO)) && 
436                (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos))))
437   {
438     SetLastWin32Error(ERROR_INVALID_PARAMETER);
439     return 0;
440   }
441   
442   Window = IntGetWindowObject(hwnd);
443
444   if(!Window)
445   {
446     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
447     return FALSE;
448   }
449   
450   switch(fnBar)
451   {
452     case SB_HORZ:
453       Info = Window->pHScroll;
454       if(Info)
455         break;
456       /* fall through */
457     case SB_VERT:
458       Info = Window->pVScroll;
459       if(Info)
460         break;
461       /* fall through */
462     case SB_CTL:
463       Info = Window->wExtra;
464       if(Info)
465         break;
466       /* fall through */
467     default:
468       IntReleaseWindowObject(Window);
469       return FALSE;
470   }
471   
472   psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
473   
474   if(lpsi->fMask == SIF_ALL)
475     Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
476   else
477     Mask = lpsi->fMask;
478
479   if(Mask & SIF_PAGE)
480   {
481     lpsi->nPage = psi->nPage;
482   }
483   
484   if(Mask & SIF_POS)
485   {
486     lpsi->nPos = psi->nPos;
487   }
488   
489   if(Mask & SIF_RANGE)
490   {
491     lpsi->nMin = psi->nMin;
492     lpsi->nMax = psi->nMax;
493   }
494   
495   IntReleaseWindowObject(Window);
496   return TRUE;
497 }
498
499
500 BOOL
501 STDCALL
502 NtUserEnableScrollBar(
503   HWND hWnd, 
504   UINT wSBflags, 
505   UINT wArrows)
506 {
507   PWINDOW_OBJECT Window;
508   PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
509   BOOL Chg = FALSE;
510   
511   Window = IntGetWindowObject(hWnd);
512
513   if(!Window)
514   {
515     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
516     return FALSE;
517   }
518   
519   switch(wSBflags)
520   {
521     case SB_BOTH:
522       InfoV = Window->pVScroll;
523       /* fall through */
524     case SB_HORZ:
525       InfoH = Window->pHScroll;
526       break;
527     case SB_VERT:
528       InfoV = Window->pVScroll;
529       break;
530     case SB_CTL:
531       InfoV = Window->wExtra;
532       break;
533     default:
534       IntReleaseWindowObject(Window);
535       return FALSE;
536   }
537   
538   if(InfoV)
539     Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
540     
541   if(InfoH)
542     Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
543
544   //if(Chg && (Window->Style & WS_VISIBLE))
545     /* FIXME - repaint scrollbars */
546
547   IntReleaseWindowObject(Window);
548   return TRUE;
549 }
550
551 DWORD
552 STDCALL
553 NtUserScrollDC(
554   HDC hDC,
555   int dx,
556   int dy,
557   CONST RECT *lprcScroll,
558   CONST RECT *lprcClip ,
559   HRGN hrgnUpdate,
560   LPRECT lprcUpdate)
561
562 {
563   UNIMPLEMENTED
564
565   return 0;
566 }
567
568 DWORD
569 STDCALL
570 NtUserSetScrollInfo(
571   HWND hwnd, 
572   int fnBar, 
573   LPSCROLLINFO lpsi, 
574   WINBOOL fRedraw)
575 {
576   PWINDOW_OBJECT Window;
577   PSCROLLBARINFO Info = NULL;
578   LPSCROLLINFO psi;
579   BOOL Chg = FALSE;
580   UINT Mask;
581   DWORD Ret;
582   
583   if(!lpsi || ((lpsi->cbSize != sizeof(SCROLLINFO)) && 
584                (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos))))
585   {
586     SetLastWin32Error(ERROR_INVALID_PARAMETER);
587     return 0;
588   }
589   
590   Window = IntGetWindowObject(hwnd);
591
592   if(!Window)
593   {
594     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
595     return 0;
596   }
597   
598   switch(fnBar)
599   {
600     case SB_HORZ:
601       Info = Window->pHScroll;
602       if(Info)
603         break;
604       /* fall through */
605     case SB_VERT:
606       Info = Window->pVScroll;
607       if(Info)
608         break;
609       /* fall through */
610     case SB_CTL:
611       Info = Window->wExtra;
612       if(Info)
613         break;
614       /* fall through */
615     default:
616       IntReleaseWindowObject(Window);
617       return 0;
618   }
619   
620   psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
621   
622   if(lpsi->fMask == SIF_ALL)
623     Mask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
624   else
625     Mask = lpsi->fMask;
626   
627   if(Mask & SIF_DISABLENOSCROLL)
628   {
629     /* FIXME */
630   }
631   
632   if((Mask & SIF_RANGE) && ((psi->nMin != lpsi->nMin) || (psi->nMax != lpsi->nMax)))
633   {
634     /* Invalid range -> range is set to (0,0) */
635     if((lpsi->nMin > lpsi->nMax) ||
636        ((UINT)(lpsi->nMax - lpsi->nMin) >= 0x80000000))
637     {
638       psi->nMin = 0;
639       psi->nMax = 0;
640       Chg = TRUE;
641     }
642     else
643     {
644       if(psi->nMin != lpsi->nMin ||
645          psi->nMax != lpsi->nMax )
646       {
647         //*action |= SA_SSI_REFRESH;
648         psi->nMin = lpsi->nMin;
649         psi->nMax = lpsi->nMax;
650         Chg = TRUE;
651       }
652     }
653   }
654   
655   if((Mask & SIF_PAGE) && (psi->nPage != lpsi->nPage))
656   {
657     psi->nPage = lpsi->nPage;
658     Chg = TRUE;
659     if(psi->nPage < 0) psi->nPage = 0;
660     else if(psi->nPage > psi->nMax - psi->nMin + 1)
661       psi->nPage = psi->nMax - psi->nMin + 1;
662   }
663   
664   if((Mask & SIF_POS) && (psi->nPos != lpsi->nPos))
665   {
666     psi->nPos = lpsi->nPos;
667     Chg = TRUE;
668     if(psi->nPos < psi->nMin)
669       psi->nPos = psi->nMin;
670     else if(psi->nPos > psi->nMax - max(psi->nPage - 1, 0))
671       psi->nPos = psi->nMax - max(psi->nPage - 1, 0);
672   }
673   
674   /* FIXME check assigned values */
675   
676   if(fRedraw && Chg && (Window->Style & WS_VISIBLE))
677   {
678     /* FIXME - Redraw */
679   }
680   
681   Ret = psi->nPos;
682   
683   IntReleaseWindowObject(Window);
684   return Ret;
685 }
686
687 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
688 DWORD
689 STDCALL
690 NtUserShowScrollBar(HWND hWnd, int wBar, DWORD bShow)
691 {
692   BOOL fShowV = (wBar == SB_VERT) ? 0 : bShow;
693   BOOL fShowH = (wBar == SB_HORZ) ? 0 : bShow;
694   PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
695   if(!Window)
696   {
697     SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
698     return FALSE;
699   }
700
701   switch (wBar)
702     {
703     case SB_CTL:
704       WinPosShowWindow (hWnd, fShowH ? SW_SHOW : SW_HIDE);
705       return TRUE;
706
707     case SB_BOTH:
708     case SB_HORZ:
709       if (fShowH)
710         {
711           fShowH = !(Window->Style & WS_HSCROLL);
712           Window->Style |= WS_HSCROLL;
713         }
714       else                      /* hide it */
715         {
716           fShowH = (Window->Style & WS_HSCROLL);
717           Window->Style &= ~WS_HSCROLL;
718         }
719       if (wBar == SB_HORZ)
720         {
721           fShowV = FALSE;
722           break;
723         }
724       /* fall through */
725
726     case SB_VERT:
727       if (fShowV)
728         {
729           fShowV = !(Window->Style & WS_VSCROLL);
730           Window->Style |= WS_VSCROLL;
731         }
732       else                      /* hide it */
733         {
734           fShowV = (Window->Style & WS_VSCROLL);
735           Window->Style &= ~WS_VSCROLL;
736         }
737       if (wBar == SB_VERT)
738         fShowH = FALSE;
739       break;
740
741     default:
742       return FALSE;             /* Nothing to do! */
743     }
744
745   if (fShowH || fShowV)         /* frame has been changed, let the window redraw itself */
746   {
747     WinPosSetWindowPos (hWnd, 0, 0, 0, 0, 0,
748                         SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
749     return TRUE;
750   }
751   return FALSE;                 /* no frame changes */
752 }
753
754 /* EOF */