scrollbar:
[reactos.git] / reactos / subsys / win32k / ntuser / scrollbar.c
index 2bfe5a4..50d4332 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: scrollbar.c,v 1.18 2003/10/25 22:57:34 navaraf Exp $
+/* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  */
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <win32k/win32k.h>
-#include <internal/safe.h>
-#include <include/object.h>
-#include <include/window.h>
-#include <include/class.h>
-#include <include/error.h>
-#include <include/winsta.h>
-#include <include/winpos.h>
-#include <include/rect.h>
-#include <include/scroll.h>
-
-//#define NDEBUG
+#include <w32k.h>
+
+#define NDEBUG
 #include <debug.h>
 
 #define MINTRACKTHUMB    8               /* Minimum size of the rectangle between the arrows */
 #define SBRG_PAGEDOWNLEFT  4 /* the page down or page left region */
 #define SBRG_BOTTOMLEFTBTN 5 /* the bottom or left button */
 
-#define SBU_TOPRIGHT   0x10
-#define SBU_BOTTOMLEFT 0x20
-#define SBU_SCROLLBOX  0x40
-
-#ifndef SIZEOF_LONG_LONG
-  // FIXME enable this!
-  //#define SIZEOF_LONG_LONG 8
-#endif
-
-/***********************************************************************
- *           MulDiv  (copied from kernel32)
- */
-static INT IntMulDiv(
-  INT nMultiplicand,
-  INT nMultiplier,
-  INT nDivisor)
-{
-#if SIZEOF_LONG_LONG >= 8
-    long long ret;
-
-    if (!nDivisor) return -1;
-
-    /* We want to deal with a positive divisor to simplify the logic. */
-    if (nDivisor < 0)
-    {
-      nMultiplicand = - nMultiplicand;
-      nDivisor = -nDivisor;
-    }
-
-    /* If the result is positive, we "add" to round. else, we subtract to round. */
-    if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
-         ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
-      ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
-    else
-      ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
-
-    if ((ret > 2147483647) || (ret < -2147483647)) return -1;
-    return ret;
-#else
-    if (!nDivisor) return -1;
-
-    /* We want to deal with a positive divisor to simplify the logic. */
-    if (nDivisor < 0)
-    {
-      nMultiplicand = - nMultiplicand;
-      nDivisor = -nDivisor;
-    }
-
-    /* If the result is positive, we "add" to round. else, we subtract to round. */
-    if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
-         ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
-      return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
-
-    return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
-
-#endif
-}
-
+#define CHANGERGSTATE(item, status) \
+  if(Info->rgstate[(item)] != (status)) \
+    Chg = TRUE; \
+  Info->rgstate[(item)] = (status);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -120,7 +56,7 @@ static INT IntMulDiv(
  * 'thumbSize' returns the size of the thumb, and 'thumbPos' returns the position of the thumb relative to the left or to
  * the top. Return TRUE if the scrollbar is vertical, FALSE if horizontal.
  */
-BOOL STDCALL
+BOOL FASTCALL
 IntGetScrollBarRect (PWINDOW_OBJECT Window, INT nBar, PRECT lprect)
 {
   BOOL vertical;
@@ -130,30 +66,26 @@ IntGetScrollBarRect (PWINDOW_OBJECT Window, INT nBar, PRECT lprect)
   switch (nBar)
     {
     case SB_HORZ:
-      lprect->left = ClientRect.left - WindowRect.left + 1;
+      lprect->left = ClientRect.left - WindowRect.left;
       lprect->top = ClientRect.bottom - WindowRect.top;
-      lprect->right = ClientRect.right - WindowRect.left - 1;
-      lprect->bottom = lprect->top + NtUserGetSystemMetrics (SM_CYHSCROLL);
-      if (Window->Style & WS_BORDER)
-       {
-         lprect->left--;
-         lprect->right++;
-       }
+      lprect->right = ClientRect.right - WindowRect.left;
+      lprect->bottom = lprect->top + UserGetSystemMetrics (SM_CYHSCROLL);
       vertical = FALSE;
       break;
 
     case SB_VERT:
-      lprect->left = (ClientRect.right - WindowRect.left);
-      lprect->top = (ClientRect.top - WindowRect.top) + 1;
-      lprect->right = (lprect->left + NtUserGetSystemMetrics (SM_CXVSCROLL));
-      lprect->bottom = (ClientRect.bottom - WindowRect.top) - 1;
-      if (Window->Style & WS_BORDER)
-       {
-         lprect->top--;
-         lprect->bottom++;
-       }
-      else if (Window->Style & WS_HSCROLL)
-       lprect->bottom++;
+      if(Window->ExStyle & WS_EX_LEFTSCROLLBAR)
+      {
+        lprect->right = ClientRect.left - WindowRect.left;
+        lprect->left = lprect->right - UserGetSystemMetrics(SM_CXVSCROLL);
+      }
+      else
+      {
+        lprect->left = ClientRect.right - WindowRect.left;
+        lprect->right = lprect->left + UserGetSystemMetrics(SM_CXVSCROLL);
+      }
+      lprect->top = ClientRect.top - WindowRect.top;
+      lprect->bottom = ClientRect.bottom - WindowRect.top;
       vertical = TRUE;
       break;
 
@@ -163,7 +95,6 @@ IntGetScrollBarRect (PWINDOW_OBJECT Window, INT nBar, PRECT lprect)
       break;
 
     default:
-      IntReleaseWindowObject(Window);
       return FALSE;
     }
 
@@ -175,27 +106,27 @@ IntCalculateThumb(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi, LPS
 {
   INT Thumb, ThumbBox, ThumbPos, cxy, mx;
   RECT ClientRect;
-  
+
   switch(idObject)
   {
     case SB_HORZ:
-      Thumb = NtUserGetSystemMetrics(SM_CXHSCROLL);
+      Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
       cxy = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
       break;
     case SB_VERT:
-      Thumb = NtUserGetSystemMetrics(SM_CYVSCROLL);
+      Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
       cxy = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
       break;
     case SB_CTL:
       IntGetClientRect (Window, &ClientRect);
       if(Window->Style & SBS_VERT)
       {
-        Thumb = NtUserGetSystemMetrics(SM_CYVSCROLL);
+        Thumb = UserGetSystemMetrics(SM_CYVSCROLL);
         cxy = ClientRect.bottom - ClientRect.top;
       }
       else
       {
-        Thumb = NtUserGetSystemMetrics(SM_CXHSCROLL);
+        Thumb = UserGetSystemMetrics(SM_CXHSCROLL);
         cxy = ClientRect.right - ClientRect.left;
       }
       break;
@@ -214,24 +145,24 @@ IntCalculateThumb(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi, LPS
   }
   else
   {
-    ThumbBox = psi->nPage ? MINTRACKTHUMB : NtUserGetSystemMetrics(SM_CXHTHUMB);
+    ThumbBox = psi->nPage ? MINTRACKTHUMB : UserGetSystemMetrics(SM_CXHTHUMB);
     cxy -= (2 * Thumb);
     if(cxy >= ThumbBox)
     {
       if(psi->nPage)
       {
-        ThumbBox = max(IntMulDiv(cxy, psi->nPage, psi->nMax - psi->nMin + 1), ThumbBox);
+        ThumbBox = max(EngMulDiv(cxy, psi->nPage, psi->nMax - psi->nMin + 1), ThumbBox);
       }
-      
+
       if(cxy > ThumbBox)
       {
         mx = psi->nMax - max(psi->nPage - 1, 0);
         if(psi->nMin < mx)
-          ThumbPos = Thumb + IntMulDiv(cxy - ThumbBox, psi->nPos - psi->nMin, mx - psi->nMin);
+          ThumbPos = Thumb + EngMulDiv(cxy - ThumbBox, psi->nPos - psi->nMin, mx - psi->nMin);
         else
           ThumbPos = Thumb + ThumbBox;
       }
-      
+
       psbi->xyThumbTop = ThumbPos;
       psbi->xyThumbBottom = ThumbPos + ThumbBox;
     }
@@ -246,336 +177,328 @@ IntCalculateThumb(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi, LPS
   return TRUE;
 }
 
-BOOL FASTCALL
-IntGetScrollInfo(PWINDOW_OBJECT Window, INT nBar, LPSCROLLINFO lpsi)
+static VOID FASTCALL
+IntUpdateSBInfo(PWINDOW_OBJECT Window, int wBar)
+{
+  PSCROLLBARINFO sbi;
+  LPSCROLLINFO psi;
+
+  ASSERT(Window);
+  ASSERT(Window->Scroll);
+
+  sbi = IntGetScrollbarInfoFromWindow(Window, wBar);
+  psi = IntGetScrollInfoFromWindow(Window, wBar);
+  IntGetScrollBarRect(Window, wBar, &(sbi->rcScrollBar));
+  IntCalculateThumb(Window, wBar, sbi, psi);
+}
+
+static BOOL FASTCALL
+co_IntGetScrollInfo(PWINDOW_OBJECT Window, INT nBar, LPSCROLLINFO lpsi)
 {
   UINT Mask;
   LPSCROLLINFO psi;
-  PSCROLLBARINFO Info;
-  
-  switch(nBar)
+
+  ASSERT_REFS(Window); 
+
+  if(!SBID_IS_VALID(nBar))
   {
-    case SB_HORZ:
-      Info = Window->pHScroll;
-      if(Info)
-        break;
-      /* fall through */
-    case SB_VERT:
-      Info = Window->pVScroll;
-      if(Info)
-        break;
-      /* fall through */
-    case SB_CTL:
-      /* FIXME
-         Send a SBM_GETSCROLLINFO message to the window. Fail if the window
-         doesn't handle the message
-      */
-      return 0;
-      
-      Info = Window->wExtra;
-      if(Info)
-        break;
-      /* fall through */
-    default:
-      return FALSE;
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d\n", nBar);
+    return FALSE;
   }
-  
-  psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
-  
-  if(lpsi->fMask == SIF_ALL)
-    Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
+
+  if(!co_IntCreateScrollBars(Window))
+    {
+      return FALSE;
+    }
+
+  psi = IntGetScrollInfoFromWindow(Window, nBar);
+
+  if (lpsi->fMask == SIF_ALL)
+    {
+      Mask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
+    }
   else
-    Mask = lpsi->fMask;
+    {
+      Mask = lpsi->fMask;
+    }
+
+  if (0 != (Mask & SIF_PAGE))
+    {
+      lpsi->nPage = psi->nPage;
+    }
+
+  if (0 != (Mask & SIF_POS))
+    {
+      lpsi->nPos = psi->nPos;
+    }
+
+  if (0 != (Mask & SIF_RANGE))
+    {
+      lpsi->nMin = psi->nMin;
+      lpsi->nMax = psi->nMax;
+    }
+
+  if (0 != (Mask & SIF_TRACKPOS))
+    {
+      lpsi->nTrackPos = psi->nTrackPos;
+    }
 
-  if(Mask & SIF_PAGE)
-  {
-    lpsi->nPage = psi->nPage;
-  }
-  
-  if(Mask & SIF_POS)
-  {
-    lpsi->nPos = psi->nPos;
-  }
-  
-  if(Mask & SIF_RANGE)
-  {
-    lpsi->nMin = psi->nMin;
-    lpsi->nMax = psi->nMax;
-  }
-  
   return TRUE;
 }
 
-DWORD FASTCALL
-IntSetScrollInfo(PWINDOW_OBJECT Window, INT nBar, LPSCROLLINFO lpsi, DWORD *Action)
+static DWORD FASTCALL
+co_IntSetScrollInfo(PWINDOW_OBJECT Window, INT nBar, LPCSCROLLINFO lpsi, BOOL bRedraw)
 {
-  PSCROLLBARINFO Info = NULL;
-  LPSCROLLINFO psi;
-  BOOL Chg = FALSE;
-  UINT Mask;
-  DWORD Ret;
-  int old;
-  
-  if(((lpsi->cbSize != sizeof(SCROLLINFO)) && 
-     (lpsi->cbSize != sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos))))
+  /*
+   * Update the scrollbar state and set action flags according to
+   * what has to be done graphics wise.
+   */
+
+  LPSCROLLINFO Info;
+  PSCROLLBARINFO psbi;
+/*   UINT new_flags;*/
+  BOOL bChangeParams = FALSE; /* don't show/hide scrollbar if params don't change */
+
+  ASSERT_REFS(Window); 
+
+  if(!SBID_IS_VALID(nBar))
   {
     SetLastWin32Error(ERROR_INVALID_PARAMETER);
-    return 0;
+    DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", nBar);
+    return FALSE;
   }
-  
-  switch(nBar)
-  {
-    case SB_HORZ:
-      Info = Window->pHScroll;
-      if(Info)
-        break;
-      /* fall through */
-    case SB_VERT:
-      Info = Window->pVScroll;
-      if(Info)
-        break;
-      /* fall through */
-    case SB_CTL:
-      /* FIXME
-         Send SBM_SETSCROLLINFO message, propably optimize it to SBM_SETPOS or SBM_SETRANGE.
-         If the window doesn't handle the message return 0
-      */
+
+  if(!co_IntCreateScrollBars(Window))
+    {
+      return FALSE;
+    }
+
+  if (lpsi->cbSize != sizeof(SCROLLINFO) &&
+      lpsi->cbSize != (sizeof(SCROLLINFO) - sizeof(lpsi->nTrackPos)))
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
       return 0;
-    
-      Info = Window->wExtra;
-      if(Info)
-        break;
-      /* fall through */
-    default:
+    }
+  if (lpsi->fMask & ~(SIF_ALL | SIF_DISABLENOSCROLL))
+    {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
       return 0;
-  }
-  
-  psi = (LPSCROLLINFO)((PSCROLLBARINFO)(Info + 1));
-  
-  if(lpsi->fMask == SIF_ALL)
-    Mask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
-  else
-    Mask = lpsi->fMask;
-  
-  if(Action)
-    *Action = 0;
-  
-  if(Mask & SIF_DISABLENOSCROLL)
-  {
-    /* FIXME */
-  }
-  
-  if((Mask & SIF_RANGE) && ((psi->nMin != lpsi->nMin) || (psi->nMax != lpsi->nMax)))
-  {
-    /* Invalid range -> range is set to (0,0) */
-    if((lpsi->nMin > lpsi->nMax) ||
-       ((UINT)(lpsi->nMax - lpsi->nMin) >= 0x80000000))
+    }
+
+  psbi = IntGetScrollbarInfoFromWindow(Window, nBar);
+  Info = IntGetScrollInfoFromWindow(Window, nBar);
+
+  /* Set the page size */
+  if (0 != (lpsi->fMask & SIF_PAGE))
     {
-      psi->nMin = 0;
-      psi->nMax = 0;
-      Chg = TRUE;
-      if(Action)
-        *Action |= SBU_SCROLLBOX;
+      if (Info->nPage != lpsi->nPage)
+        {
+          Info->nPage = lpsi->nPage;
+          bChangeParams = TRUE;
+        }
     }
-    else
+
+  /* Set the scroll pos */
+  if (0 != (lpsi->fMask & SIF_POS))
     {
-      if(psi->nMin != lpsi->nMin ||
-         psi->nMax != lpsi->nMax )
-      {
-        //*action |= SA_SSI_REFRESH;
-        psi->nMin = lpsi->nMin;
-        psi->nMax = lpsi->nMax;
-        Chg = TRUE;
-        if(Action)
-          *Action |= SBU_SCROLLBOX;
-      }
+      if (Info->nPos != lpsi->nPos)
+        {
+          Info->nPos = lpsi->nPos;
+        }
     }
-  }
-  
-  if((Mask & SIF_PAGE) && (psi->nPage != lpsi->nPage))
-  {
-    old = psi->nPage;
-    psi->nPage = lpsi->nPage;
-    if(psi->nPage < 0) psi->nPage = 0;
-    else if(psi->nPage > psi->nMax - psi->nMin + 1)
-      psi->nPage = psi->nMax - psi->nMin + 1;
-    
-    if(old != psi->nPage)
+
+  /* Set the scroll range */
+  if (0 != (lpsi->fMask & SIF_RANGE))
     {
-      Chg = TRUE;
-      if(Action)
-        *Action |= SBU_SCROLLBOX;
+      /* Invalid range -> range is set to (0,0) */
+      if (lpsi->nMin > lpsi->nMax ||
+          0x80000000 <= (UINT)(lpsi->nMax - lpsi->nMin))
+        {
+          Info->nMin = 0;
+          Info->nMax = 0;
+          bChangeParams = TRUE;
+        }
+      else if (Info->nMin != lpsi->nMin || Info->nMax != lpsi->nMax)
+        {
+          Info->nMin = lpsi->nMin;
+          Info->nMax = lpsi->nMax;
+          bChangeParams = TRUE;
+        }
     }
-  }
-  
-  if((Mask & SIF_POS) && (psi->nPos != lpsi->nPos))
-  {
-    old = psi->nPos;
-    psi->nPos = lpsi->nPos;
-    if(psi->nPos < psi->nMin)
-      psi->nPos = psi->nMin;
-    else if(psi->nPos > psi->nMax - max(psi->nPage - 1, 0))
-      psi->nPos = psi->nMax - max(psi->nPage - 1, 0);
-    
-    if(old != psi->nPos)
+
+  /* Make sure the page size is valid */
+  if (Info->nPage < 0)
     {
-      Chg = TRUE;
-      if(Action)
-        *Action |= SBU_SCROLLBOX;
+      Info->nPage = 0;
     }
-  }
-  
-  Ret = psi->nPos;
-  
-  return Ret;
+  else if (Info->nMax - Info->nMin + 1 < Info->nPage)
+    {
+      Info->nPage = Info->nMax - Info->nMin + 1;
+    }
+
+  /* Make sure the pos is inside the range */
+  if (Info->nPos < Info->nMin)
+    {
+      Info->nPos = Info->nMin;
+    }
+  else if (Info->nPos > Info->nMax - max(Info->nPage - 1, 0))
+    {
+      Info->nPos = Info->nMax - max(Info->nPage - 1, 0);
+    }
+
+  /*
+   * Don't change the scrollbar state if SetScrollInfo is just called
+   * with SIF_DISABLENOSCROLL
+   */
+  if (0 == (lpsi->fMask & SIF_ALL))
+    {
+      return Info->nPos;
+    }
+
+  /* Check if the scrollbar should be hidden or disabled */
+  if (0 != (lpsi->fMask & (SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL)))
+    {
+      if (Info->nMin >= (int)(Info->nMax - max(Info->nPage - 1, 0)))
+        {
+          /* Hide or disable scroll-bar */
+          if (0 != (lpsi->fMask & SIF_DISABLENOSCROLL))
+            {
+/*            new_flags = ESB_DISABLE_BOTH;*/
+            }
+          else if ((nBar != SB_CTL) && bChangeParams)
+            {
+              co_UserShowScrollBar(Window, nBar, FALSE);
+              return Info->nPos;
+            }
+        }
+      else  /* Show and enable scroll-bar */
+        {
+/*         new_flags = 0;*/
+          if ((nBar != SB_CTL) && bChangeParams)
+            {
+              co_UserShowScrollBar(Window, nBar, TRUE);
+            }
+        }
+
+#if 0
+      if (infoPtr->flags != new_flags) /* check arrow flags */
+        {
+          infoPtr->flags = new_flags;
+          *Action |= SA_SSI_REPAINT_ARROWS;
+        }
+#endif
+    }
+
+  if (bRedraw)
+    {
+      RECT UpdateRect = psbi->rcScrollBar;
+      UpdateRect.left -= Window->ClientRect.left - Window->WindowRect.left;
+      UpdateRect.right -= Window->ClientRect.left - Window->WindowRect.left;
+      UpdateRect.top -= Window->ClientRect.top - Window->WindowRect.top;
+      UpdateRect.bottom -= Window->ClientRect.top - Window->WindowRect.top;
+      co_UserRedrawWindow(Window, &UpdateRect, 0, RDW_INVALIDATE | RDW_FRAME);
+    }
+
+   /* Return current position */
+   return Info->nPos;
 }
 
 BOOL FASTCALL
-IntGetScrollBarInfo(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi)
+co_IntGetScrollBarInfo(PWINDOW_OBJECT Window, LONG idObject, PSCROLLBARINFO psbi)
 {
   INT Bar;
   PSCROLLBARINFO sbi;
   LPSCROLLINFO psi;
-  
-  switch(idObject)
+
+  ASSERT_REFS(Window); 
+
+  Bar = SBOBJ_TO_SBID(idObject);
+
+  if(!SBID_IS_VALID(Bar))
   {
-    case OBJID_HSCROLL:
-      if(Window->pHScroll)
-      {
-        Bar = SB_HORZ;
-        sbi = Window->pHScroll;
-        break;
-      }
-      /* fall through */
-    case OBJID_VSCROLL:
-      if(Window->pVScroll)
-      {
-        Bar = SB_VERT;
-        sbi = Window->pVScroll;
-        break;
-      }
-      /* fall through */
-    case OBJID_CLIENT:
-    
-      /* FIXME
-        Send a SBM_GETSCROLLBARINFO message if Window is not a system scrollbar.
-        If the window doesn't handle the message return FALSE.
-      */
-      return FALSE;
-    
-      if(Window->wExtra)
-      {
-        Bar = SB_CTL;
-        sbi = Window->wExtra;
-        break;
-      }
-      /* fall through */
-    default:
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      return FALSE;
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    DPRINT1("Trying to get scrollinfo for unknown scrollbar type %d\n", Bar);
+    return FALSE;
   }
-  
-  psi = (LPSCROLLINFO)((PSCROLLBARINFO)(sbi + 1));
+
+  if(!co_IntCreateScrollBars(Window))
+    {
+      return FALSE;
+    }
+
+  sbi = IntGetScrollbarInfoFromWindow(Window, Bar);
+  psi = IntGetScrollInfoFromWindow(Window, Bar);
 
   IntGetScrollBarRect(Window, Bar, &(sbi->rcScrollBar));
   IntCalculateThumb(Window, Bar, sbi, psi);
-  
+
   RtlCopyMemory(psbi, sbi, sizeof(SCROLLBARINFO));
-  
+
   return TRUE;
 }
 
-DWORD FASTCALL 
-IntCreateScrollBar(PWINDOW_OBJECT Window, LONG idObject)
+BOOL FASTCALL
+co_IntCreateScrollBars(PWINDOW_OBJECT Window)
 {
   PSCROLLBARINFO psbi;
   LPSCROLLINFO psi;
   LRESULT Result;
+  ULONG Size, s;
   INT i;
 
-  psbi = ExAllocatePool(PagedPool, sizeof(SCROLLBARINFO) + sizeof(SCROLLINFO));
-  if(!psbi)
+  ASSERT_REFS(Window); 
+
+  if(Window->Scroll)
+  {
+    /* no need to create it anymore */
+    return TRUE;
+  }
+
+  /* allocate memory for all scrollbars (HORZ, VERT, CONTROL) */
+  Size = 3 * (sizeof(WINDOW_SCROLLINFO));
+  if(!(Window->Scroll = ExAllocatePoolWithTag(PagedPool, Size, TAG_SBARINFO)))
+  {
+    DPRINT1("Unable to allocate memory for scrollbar information for window 0x%x\n", Window->hSelf);
     return FALSE;
-    
-  psi = (LPSCROLLINFO)((PSCROLLBARINFO)(psbi + 1));
-  
-  psi->cbSize = sizeof(LPSCROLLINFO);
-  psi->nMin = 0;
-  psi->nMax = 100;
-  psi->nPage = 0;
-  psi->nPos = 0;
-  psi->nTrackPos = 0;
-
-  Result = WinPosGetNonClientSize(Window->Self,
+  }
+
+  RtlZeroMemory(Window->Scroll, Size);
+
+  Result = co_WinPosGetNonClientSize(Window->hSelf,
                                  &Window->WindowRect,
                                  &Window->ClientRect);
 
-  psbi->cbSize = sizeof(SCROLLBARINFO);
+  for(s = SB_HORZ; s <= SB_VERT; s++)
+  {
+    psbi = IntGetScrollbarInfoFromWindow(Window, s);
+    psbi->cbSize = sizeof(SCROLLBARINFO);
+    for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
+      psbi->rgstate[i] = 0;
 
-  for (i = 0; i < CCHILDREN_SCROLLBAR + 1; i++)
-    psbi->rgstate[i] = 0;
+    psi = IntGetScrollInfoFromWindow(Window, s);
+    psi->cbSize = sizeof(LPSCROLLINFO);
+    psi->nMax = 100;
 
-  switch(idObject)
-  {
-    case SB_HORZ:
-      Window->pHScroll = psbi;
-      break;
-    case SB_VERT:
-      Window->pVScroll = psbi;
-      break;
-    case SB_CTL:
-      Window->wExtra = psbi;
-      break;
-    default:
-      ExFreePool(psbi);
-      return FALSE;
+    IntGetScrollBarRect(Window, s, &(psbi->rcScrollBar));
+    IntCalculateThumb(Window, s, psbi, psi);
   }
 
-  IntGetScrollBarRect(Window, idObject, &(psbi->rcScrollBar));
-  IntCalculateThumb(Window, idObject, psbi, psi);
-
-  return 0;
+  return TRUE;
 }
 
-BOOL FASTCALL 
-IntDestroyScrollBar(PWINDOW_OBJECT Window, LONG idObject)
+BOOL FASTCALL
+IntDestroyScrollBars(PWINDOW_OBJECT Window)
 {
-  switch(idObject)
+  if(Window->Scroll)
   {
-    case SB_HORZ:
-      if(Window->pHScroll)
-      {
-        ExFreePool(Window->pHScroll);
-        Window->pHScroll = NULL;
-        return TRUE;
-      }
-      return FALSE;
-    case SB_VERT:
-      if(Window->pVScroll)
-      {
-        ExFreePool(Window->pVScroll);
-        Window->pVScroll = NULL;
-        return TRUE;
-      }
-      return FALSE;
-    case SB_CTL:
-      if(Window->wExtra)
-      {
-        ExFreePool(Window->wExtra);
-        Window->wExtra = NULL;
-        return TRUE;
-      }
-      return FALSE;
+    ExFreePool(Window->Scroll);
+    Window->Scroll = NULL;
+    return TRUE;
   }
   return FALSE;
 }
 
-#define CHANGERGSTATE(item, status) \
-  if(Info->rgstate[(item)] != (status)) \
-    Chg = TRUE; \
-  Info->rgstate[(item)] = (status); 
-
-
 BOOL STDCALL
 IntEnableScrollBar(BOOL Horz, PSCROLLBARINFO Info, UINT wArrows)
 {
@@ -623,23 +546,26 @@ NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
   SCROLLBARINFO sbi;
   PWINDOW_OBJECT Window;
   BOOL Ret;
+  DECLARE_RETURN(BOOL);
+  
+  DPRINT("Enter NtUserGetScrollBarInfo\n");
+  UserEnterExclusive();
 
   Status = MmCopyFromCaller(&sbi, psbi, sizeof(SCROLLBARINFO));
   if(!NT_SUCCESS(Status) || (sbi.cbSize != sizeof(SCROLLBARINFO)))
   {
     SetLastNtError(Status);
-    return FALSE;
+    RETURN(FALSE);
   }
 
-  Window = IntGetWindowObject(hWnd);
-
-  if(!Window)
+  if(!(Window = UserGetWindowObject(hWnd)))
   {
-    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-    return FALSE;
+    RETURN(FALSE);
   }
 
-  Ret = IntGetScrollBarInfo(Window, idObject, &sbi);
+  UserReferenceWindowObjectCo(Window);
+  Ret = co_IntGetScrollBarInfo(Window, idObject, &sbi);
+  UserDereferenceWindowObjectCo(Window);
 
   Status = MmCopyToCaller(psbi, &sbi, sizeof(SCROLLBARINFO));
   if(!NT_SUCCESS(Status))
@@ -647,236 +573,340 @@ NtUserGetScrollBarInfo(HWND hWnd, LONG idObject, PSCROLLBARINFO psbi)
     SetLastNtError(Status);
     Ret = FALSE;
   }
-  IntReleaseWindowObject(Window);
-  return Ret;
+
+  RETURN( Ret);
+  
+CLEANUP:
+  DPRINT("Leave NtUserGetScrollBarInfo, ret=%i\n",_ret_);
+  UserLeave();
+  END_CLEANUP;
+  
 }
 
 
 BOOL
 STDCALL
-NtUserGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
+NtUserGetScrollInfo(HWND hWnd, int fnBar, LPSCROLLINFO lpsi)
 {
   NTSTATUS Status;
   PWINDOW_OBJECT Window;
   SCROLLINFO psi;
   DWORD sz;
   BOOL Ret;
+  DECLARE_RETURN(BOOL);
   
-  Status = MmCopyFromCaller(&psi, lpsi, sizeof(SCROLLINFO) - sizeof(psi.nTrackPos));
-  if(!NT_SUCCESS(Status) || 
+  DPRINT("Enter NtUserGetScrollInfo\n");
+  UserEnterShared();
+
+  Status = MmCopyFromCaller(&psi.cbSize, &(lpsi->cbSize), sizeof(UINT));
+  if(!NT_SUCCESS(Status) ||
      !((psi.cbSize == sizeof(SCROLLINFO)) || (psi.cbSize == sizeof(SCROLLINFO) - sizeof(psi.nTrackPos))))
   {
     SetLastNtError(Status);
-    return FALSE;
+    RETURN(FALSE);
   }
   sz = psi.cbSize;
-  
-  Window = IntGetWindowObject(hwnd);
+  Status = MmCopyFromCaller(&psi, lpsi, sz);
+  if (!NT_SUCCESS(Status))
+  {
+    SetLastNtError(Status);
+    RETURN(FALSE);
+  }
 
-  if(!Window)
+  if(!(Window = UserGetWindowObject(hWnd)))
   {
-    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-    return FALSE;
+    RETURN(FALSE);
   }
-  
-  Ret = IntGetScrollInfo(Window, fnBar, &psi);
-  
-  IntReleaseWindowObject(Window);
-  
+
+  UserReferenceWindowObjectCo(Window);   
+  Ret = co_IntGetScrollInfo(Window, fnBar, &psi);
+  UserDereferenceWindowObjectCo(Window);
+
   Status = MmCopyToCaller(lpsi, &psi, sz);
   if(!NT_SUCCESS(Status))
   {
     SetLastNtError(Status);
-    return FALSE;
+    RETURN( FALSE);
   }
+
+  RETURN( Ret);
   
-  return Ret;
+CLEANUP:
+  DPRINT("Leave NtUserGetScrollInfo, ret=%i\n",_ret_);
+  UserLeave();
+  END_CLEANUP;  
 }
 
 
 BOOL
 STDCALL
 NtUserEnableScrollBar(
-  HWND hWnd, 
-  UINT wSBflags, 
+  HWND hWnd,
+  UINT wSBflags,
   UINT wArrows)
 {
-  PWINDOW_OBJECT Window;
+  PWINDOW_OBJECT Window = NULL;
   PSCROLLBARINFO InfoV = NULL, InfoH = NULL;
   BOOL Chg = FALSE;
+  DECLARE_RETURN(BOOL);
   
-  Window = IntGetWindowObject(hWnd);
+  DPRINT("Enter NtUserEnableScrollBar\n");
+  UserEnterExclusive();
 
-  if(!Window)
+  if(!(Window = UserGetWindowObject(hWnd)))
   {
-    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-    return FALSE;
+    RETURN(FALSE);
   }
-  
+  UserReferenceWindowObjectCo(Window);
+
+  if(wSBflags == SB_CTL)
+  {
+    /* FIXME Enable or Disable SB Ctrl*/
+    DPRINT1("Enable Scrollbar SB_CTL\n");
+    InfoV = IntGetScrollbarInfoFromWindow(Window, SB_CTL);
+    Chg = IntEnableScrollBar(FALSE, InfoV ,wArrows);
+    /* Chg? Scrollbar is Refresh in user32/controls/scrollbar.c. */
+
+    RETURN(TRUE);
+  }
+
+  if(wSBflags != SB_BOTH && !SBID_IS_VALID(wSBflags))
+  {
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", wSBflags);
+    RETURN(FALSE);
+  }
+
+  if(!co_IntCreateScrollBars(Window))
+    {
+      RETURN( FALSE);
+    }
+
   switch(wSBflags)
   {
     case SB_BOTH:
-      InfoV = Window->pVScroll;
+      InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
       /* fall through */
     case SB_HORZ:
-      InfoH = Window->pHScroll;
+      InfoH = IntGetScrollbarInfoFromWindow(Window, SB_HORZ);
       break;
     case SB_VERT:
-      InfoV = Window->pVScroll;
-      break;
-    case SB_CTL:
-      InfoV = Window->wExtra;
+      InfoV = IntGetScrollbarInfoFromWindow(Window, SB_VERT);
       break;
     default:
-      IntReleaseWindowObject(Window);
-      return FALSE;
+      RETURN(FALSE);
   }
-  
+
   if(InfoV)
     Chg = IntEnableScrollBar(FALSE, InfoV, wArrows);
-    
+
   if(InfoH)
     Chg = (IntEnableScrollBar(TRUE, InfoH, wArrows) || Chg);
 
   //if(Chg && (Window->Style & WS_VISIBLE))
     /* FIXME - repaint scrollbars */
 
-  IntReleaseWindowObject(Window);
-  return TRUE;
+  RETURN( TRUE);
+  
+CLEANUP:
+  if (Window) UserDereferenceWindowObjectCo(Window);
+
+  DPRINT("Leave NtUserEnableScrollBar, ret=%i\n",_ret_);
+  UserLeave();
+  END_CLEANUP;
 }
 
-DWORD
+BOOL
 STDCALL
-NtUserScrollDC(
-  HDC hDC,
-  int dx,
-  int dy,
-  CONST RECT *lprcScroll,
-  CONST RECT *lprcClip ,
-  HRGN hrgnUpdate,
-  LPRECT lprcUpdate)
-
+NtUserSetScrollBarInfo(
+  HWND hWnd,
+  LONG idObject,
+  SETSCROLLBARINFO *info)
 {
-  UNIMPLEMENTED
+  PWINDOW_OBJECT Window = NULL;
+  SETSCROLLBARINFO Safeinfo;
+  PSCROLLBARINFO sbi;
+  LPSCROLLINFO psi;
+  NTSTATUS Status;
+  LONG Obj;
+  DECLARE_RETURN(BOOL);
+
+  DPRINT("Enter NtUserSetScrollBarInfo\n");
+  UserEnterExclusive();
+
+  if(!(Window = UserGetWindowObject(hWnd)))
+  {
+    RETURN( FALSE);
+  }
+  UserReferenceWindowObjectCo(Window);
+
+  Obj = SBOBJ_TO_SBID(idObject);
+  if(!SBID_IS_VALID(Obj))
+  {
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    DPRINT1("Trying to set scrollinfo for unknown scrollbar type %d", Obj);
+    RETURN( FALSE);
+  }
+
+  if(!co_IntCreateScrollBars(Window))
+    {
+      RETURN(FALSE);
+    }
+
+  Status = MmCopyFromCaller(&Safeinfo, info, sizeof(SETSCROLLBARINFO));
+  if(!NT_SUCCESS(Status))
+  {
+    SetLastNtError(Status);
+    RETURN(FALSE);
+  }
+
+  sbi = IntGetScrollbarInfoFromWindow(Window, Obj);
+  psi = IntGetScrollInfoFromWindow(Window, Obj);
 
-  return 0;
+  psi->nTrackPos = Safeinfo.nTrackPos;
+  sbi->reserved = Safeinfo.reserved;
+  RtlCopyMemory(&sbi->rgstate, &Safeinfo.rgstate, sizeof(Safeinfo.rgstate));
+
+  RETURN(TRUE);
+  
+CLEANUP:
+  if (Window) UserDereferenceWindowObjectCo(Window);
+
+  DPRINT("Leave NtUserSetScrollBarInfo, ret=%i\n",_ret_);
+  UserLeave();
+  END_CLEANUP;
 }
 
 DWORD
 STDCALL
 NtUserSetScrollInfo(
-  HWND hwnd, 
-  int fnBar, 
-  LPSCROLLINFO lpsi, 
-  DWORD *Changed)
+  HWND hWnd,
+  int fnBar,
+  LPCSCROLLINFO lpsi,
+  BOOL bRedraw)
 {
-  PWINDOW_OBJECT Window;
+  PWINDOW_OBJECT Window = NULL;
   NTSTATUS Status;
   SCROLLINFO ScrollInfo;
-  DWORD Ret, Action;
+  DECLARE_RETURN(DWORD);
   
-  Window = IntGetWindowObject(hwnd);
+  DPRINT("Enter NtUserSetScrollInfo\n");
+  UserEnterExclusive();
 
-  if(!Window)
+  if(!(Window = UserGetWindowObject(hWnd)))
   {
-    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-    return 0;
+    RETURN( 0);
   }
-  
+  UserReferenceWindowObjectCo(Window);
+
   Status = MmCopyFromCaller(&ScrollInfo, lpsi, sizeof(SCROLLINFO) - sizeof(ScrollInfo.nTrackPos));
   if(!NT_SUCCESS(Status))
   {
-    IntReleaseWindowObject(Window);
     SetLastNtError(Status);
-    return 0;
-  }
-  
-  Ret = IntSetScrollInfo(Window, fnBar, &ScrollInfo, &Action);
-  
-  if(Changed)
-  {
-    if(Action && (Window->Style & WS_VISIBLE))
-    {
-      MmCopyToCaller(Changed, &Action, sizeof(DWORD));
-    }
-    else
-    {
-      MmCopyToCaller(Changed, &Action, sizeof(DWORD));
-    }
+    RETURN( 0);
   }
+
+  RETURN(co_IntSetScrollInfo(Window, fnBar, &ScrollInfo, bRedraw));
+
+CLEANUP:
+  if (Window) UserDereferenceWindowObjectCo(Window); 
+   
+  DPRINT("Leave NtUserSetScrollInfo, ret=%i\n",_ret_);
+  UserLeave();
+  END_CLEANUP;
   
-  IntReleaseWindowObject(Window);
-  
-  return Ret;
 }
 
 /* Ported from WINE20020904 (SCROLL_ShowScrollBar) */
-DWORD
-STDCALL
-NtUserShowScrollBar(HWND hWnd, int wBar, DWORD bShow)
+DWORD FASTCALL
+co_UserShowScrollBar(PWINDOW_OBJECT Window, int wBar, DWORD bShow)
 {
-  BOOL fShowV = (wBar == SB_VERT) ? 0 : bShow;
-  BOOL fShowH = (wBar == SB_HORZ) ? 0 : bShow;
-  PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
-  if(!Window)
-  {
-    SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
-    return FALSE;
-  }
-
-  switch (wBar)
+   DWORD Style, OldStyle;
+
+   ASSERT_REFS(Window);
+
+   switch(wBar)
+   {
+     case SB_HORZ:
+       Style = WS_HSCROLL;
+       break;
+     case SB_VERT:
+       Style = WS_VSCROLL;
+       break;
+     case SB_BOTH:
+       Style = WS_HSCROLL | WS_VSCROLL;
+       break;
+     case SB_CTL:
+       Style = 0;
+       break;
+     default:
+       SetLastWin32Error(ERROR_INVALID_PARAMETER);
+       return( FALSE);
+   }
+
+  if(!co_IntCreateScrollBars(Window))
     {
-    case SB_CTL:
-      WinPosShowWindow (hWnd, fShowH ? SW_SHOW : SW_HIDE);
-      return TRUE;
+      return( FALSE);
+    }
 
-    case SB_BOTH:
-    case SB_HORZ:
-      if (fShowH)
-       {
-         fShowH = !(Window->Style & WS_HSCROLL);
-         Window->Style |= WS_HSCROLL;
-       }
-      else                     /* hide it */
-       {
-         fShowH = (Window->Style & WS_HSCROLL);
-         Window->Style &= ~WS_HSCROLL;
-       }
-      if (wBar == SB_HORZ)
-       {
-         fShowV = FALSE;
-         break;
-       }
-      /* fall through */
+   if (wBar == SB_CTL)
+   {
+      IntUpdateSBInfo(Window, SB_CTL);
+
+      co_WinPosShowWindow(Window->hSelf, bShow ? SW_SHOW : SW_HIDE);
+      return( TRUE);
+   }
+
+   OldStyle = Window->Style;
+   if(bShow)
+     Window->Style |= Style;
+   else
+     Window->Style &= ~Style;
+
+   if(Window->Style != OldStyle)
+   {
+     if(Window->Style & WS_HSCROLL)
+       IntUpdateSBInfo(Window, SB_HORZ);
+     if(Window->Style & WS_VSCROLL)
+       IntUpdateSBInfo(Window, SB_VERT);
+
+     if(Window->Style & WS_VISIBLE)
+     {
+       /* Frame has been changed, let the window redraw itself */
+       co_WinPosSetWindowPos(Window->hSelf, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+          SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOSENDCHANGING);
+     }
+   }
+
+   return( TRUE);
+}
 
-    case SB_VERT:
-      if (fShowV)
-       {
-         fShowV = !(Window->Style & WS_VSCROLL);
-         Window->Style |= WS_VSCROLL;
-       }
-      else                     /* hide it */
-       {
-         fShowV = (Window->Style & WS_VSCROLL);
-         Window->Style &= ~WS_VSCROLL;
-       }
-      if (wBar == SB_VERT)
-       fShowH = FALSE;
-      break;
 
-    default:
-      return FALSE;            /* Nothing to do! */
-    }
+DWORD STDCALL
+NtUserShowScrollBar(HWND hWnd, int wBar, DWORD bShow)
+{
+   PWINDOW_OBJECT Window;
+   DECLARE_RETURN(DWORD);
+   DWORD ret;
+   
+   DPRINT("Enter NtUserShowScrollBar\n");
+   UserEnterExclusive();
+   
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(0);
+   }
+   
+   UserReferenceWindowObjectCo(Window);
+   ret = co_UserShowScrollBar(Window, wBar, bShow);
+   UserDereferenceWindowObjectCo(Window);
+   
+   RETURN(ret);
+   
+CLEANUP:
+   DPRINT("Leave NtUserShowScrollBar,  ret%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 
-  IntReleaseWindowObject(Window);
-  
-  if (fShowH || fShowV)                /* frame has been changed, let the window redraw itself */
-  {
-    WinPosSetWindowPos (hWnd, 0, 0, 0, 0, 0,
-                        SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
-    return TRUE;
-  }
-  return FALSE;                        /* no frame changes */
 }
-
 /* EOF */