[PATCH 3/5] uxtheme: Support drawing themed standard scroll bars.

Zhiyi Zhang zzhang at codeweavers.com
Wed Jul 7 03:13:12 CDT 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=39821
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/user32/controls.h     |  22 --
 dlls/user32/hook.c         |   1 +
 dlls/user32/scroll.c       |  47 +++-
 dlls/user32/user_private.h |   3 +
 dlls/uxtheme/scrollbar.c   | 464 +++++--------------------------------
 dlls/uxtheme/system.c      |   1 +
 dlls/uxtheme/uxthemedll.h  |   4 +
 include/winuser.h          |  26 +++
 8 files changed, 134 insertions(+), 434 deletions(-)

diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h
index 25ff4fe05ff..bf32097f95c 100644
--- a/dlls/user32/controls.h
+++ b/dlls/user32/controls.h
@@ -180,28 +180,6 @@ extern void NC_GetSysPopupPos( HWND hwnd, RECT* rect ) DECLSPEC_HIDDEN;
 
 /* scrollbar */
 
-/* Scroll-bar hit testing */
-enum SCROLL_HITTEST
-{
-    SCROLL_NOWHERE,      /* Outside the scroll bar */
-    SCROLL_TOP_ARROW,    /* Top or left arrow */
-    SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
-    SCROLL_THUMB,        /* Thumb rectangle */
-    SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
-    SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
-};
-
-/* Scroll bar tracking information */
-struct SCROLL_TRACKING_INFO
-{
-    HWND win;                       /* Tracking window */
-    INT bar;                        /* SB_HORZ / SB_VERT / SB_CTL */
-    INT thumb_pos;                  /* Thumb position */
-    INT thumb_val;                  /* Current thumb value from thumb position */
-    BOOL vertical;                  /* Is scroll bar vertical */
-    enum SCROLL_HITTEST hit_test;   /* Hit Test code of the last button-down event */
-};
-
 extern void SCROLL_DrawNCScrollBar( HWND hwnd, HDC hdc, BOOL draw_horizontal, BOOL draw_vertical ) DECLSPEC_HIDDEN;
 extern void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTEST hit_test,
                                   const struct SCROLL_TRACKING_INFO *tracking_info, BOOL arrows,
diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c
index c4e71ec49b6..d20bae7970d 100644
--- a/dlls/user32/hook.c
+++ b/dlls/user32/hook.c
@@ -84,6 +84,7 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
 static struct user_api_hook original_user_api =
 {
     USER_DefDlgProc,
+    USER_ScrollBarDraw,
     USER_ScrollBarProc,
 };
 static struct user_api_hook hooked_user_api;
diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c
index 9a22e930332..c4c06476b9c 100644
--- a/dlls/user32/scroll.c
+++ b/dlls/user32/scroll.c
@@ -567,10 +567,10 @@ static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
     SelectObject( hdc, hSaveBrush );
 }
 
-static void SCROLL_DoDrawScrollBar( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTEST hit_test,
-                                    const struct SCROLL_TRACKING_INFO *tracking_info, BOOL arrows,
-                                    BOOL interior, RECT *rect, INT arrowSize, INT thumbPos,
-                                    INT thumbSize, BOOL vertical )
+void WINAPI USER_ScrollBarDraw( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTEST hit_test,
+                                const struct SCROLL_TRACKING_INFO *tracking_info, BOOL arrows,
+                                BOOL interior, RECT *rect, INT arrowSize, INT thumbPos,
+                                INT thumbSize, BOOL vertical )
 {
     SCROLLBAR_INFO *infoPtr;
 
@@ -678,8 +678,8 @@ void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, INT bar, enum SCROLL_HITTEST hit_
           tracking_info->thumb_val, tracking_info->vertical, tracking_info->hit_test, draw_arrows,
           draw_interior, wine_dbgstr_rect(&rect), arrow_size, thumb_pos, thumb_size, vertical,
           GetCapture());
-    SCROLL_DoDrawScrollBar( hwnd, hdc, bar, hit_test, tracking_info, draw_arrows, draw_interior,
-                            &rect, arrow_size, thumb_pos, thumb_size, vertical );
+    user_api->pScrollBarDraw( hwnd, hdc, bar, hit_test, tracking_info, draw_arrows, draw_interior,
+                              &rect, arrow_size, thumb_pos, thumb_size, vertical );
 }
 
 void SCROLL_DrawNCScrollBar( HWND hwnd, HDC hdc, BOOL draw_horizontal, BOOL draw_vertical )
@@ -764,6 +764,7 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
 
     enum SCROLL_HITTEST hittest;
     HWND hwndOwner, hwndCtl;
+    TRACKMOUSEEVENT tme;
     BOOL vertical;
     INT arrowSize, thumbSize, thumbPos;
     RECT rect;
@@ -771,7 +772,8 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
 
     SCROLLBAR_INFO *infoPtr = SCROLL_GetInternalInfo( hwnd, nBar, FALSE );
     if (!infoPtr) return;
-    if ((g_tracking_info.hit_test == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN))
+    if ((g_tracking_info.hit_test == SCROLL_NOWHERE)
+        && (msg != WM_LBUTTONDOWN && msg != WM_MOUSEMOVE && msg != WM_MOUSELEAVE))
 		  return;
 
     if (nBar == SB_CTL && (GetWindowLongW( hwnd, GWL_STYLE ) & (SBS_SIZEGRIP | SBS_SIZEBOX)))
@@ -821,8 +823,29 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
           break;
 
       case WM_MOUSEMOVE:
-          hittest = SCROLL_HitTest( hwnd, nBar, pt, TRUE );
+          hittest = SCROLL_HitTest( hwnd, nBar, pt, vertical == g_tracking_info.vertical && GetCapture() == hwnd );
           prevPt = pt;
+
+          if (nBar != SB_CTL)
+              break;
+
+          tme.cbSize = sizeof(tme);
+          tme.dwFlags = TME_QUERY;
+          TrackMouseEvent( &tme );
+          if (!(tme.dwFlags & TME_LEAVE) || tme.hwndTrack != hwnd)
+          {
+              tme.dwFlags = TME_LEAVE;
+              tme.hwndTrack = hwnd;
+              TrackMouseEvent( &tme );
+          }
+
+          break;
+
+      case WM_MOUSELEAVE:
+          if (nBar != SB_CTL)
+              return;
+
+          hittest = SCROLL_NOWHERE;
           break;
 
       case WM_LBUTTONUP:
@@ -847,6 +870,8 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
     switch (g_tracking_info.hit_test)
     {
     case SCROLL_NOWHERE:  /* No tracking in progress */
+        if (msg == WM_MOUSEMOVE || msg == WM_MOUSELEAVE)
+            SCROLL_DrawScrollBar( hwnd, hdc, nBar, hittest, &g_tracking_info, TRUE, TRUE );
         break;
 
     case SCROLL_TOP_ARROW:
@@ -898,7 +923,7 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
         {
             SCROLL_DrawScrollBar( hwnd, hdc, nBar, SCROLL_NOWHERE, &g_tracking_info, FALSE, TRUE );
         }
-        else  /* WM_MOUSEMOVE */
+        else if (msg == WM_MOUSEMOVE)
         {
             INT pos;
 
@@ -986,6 +1011,8 @@ static void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt)
         /* Terminate tracking */
         g_tracking_info.win = 0;
         SCROLL_MovingThumb = FALSE;
+        hittest = SCROLL_NOWHERE;
+        SCROLL_DrawScrollBar( hwnd, hdc, nBar, hittest, &g_tracking_info, TRUE, TRUE );
     }
 
     ReleaseDC( hwnd, hdc );
@@ -1021,6 +1048,7 @@ void SCROLL_TrackScrollBar( HWND hwnd, INT scrollbar, POINT pt )
         if (CallMsgFilterW( &msg, MSGF_SCROLLBAR )) continue;
         if (msg.message == WM_LBUTTONUP ||
             msg.message == WM_MOUSEMOVE ||
+            msg.message == WM_MOUSELEAVE ||
             (msg.message == WM_SYSTIMER && msg.wParam == SCROLL_TIMER))
         {
             pt.x = (short)LOWORD(msg.lParam) - rect.left;
@@ -1356,6 +1384,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA
         break;
     case WM_LBUTTONUP:
     case WM_MOUSEMOVE:
+    case WM_MOUSELEAVE:
     case WM_SYSTIMER:
         {
             POINT pt;
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 8750008a5fb..7c4d9015976 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -389,5 +389,8 @@ struct png_funcs
 extern struct user_api_hook *user_api DECLSPEC_HIDDEN;
 LRESULT WINAPI USER_DefDlgProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN;
 LRESULT WINAPI USER_ScrollBarProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN;
+void WINAPI USER_ScrollBarDraw(HWND, HDC, INT, enum SCROLL_HITTEST,
+                               const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, INT, INT,
+                               INT, BOOL) DECLSPEC_HIDDEN;
 
 #endif /* __WINE_USER_PRIVATE_H */
diff --git a/dlls/uxtheme/scrollbar.c b/dlls/uxtheme/scrollbar.c
index 393b45a831d..40fdbf4b89a 100644
--- a/dlls/uxtheme/scrollbar.c
+++ b/dlls/uxtheme/scrollbar.c
@@ -20,8 +20,6 @@
  */
 
 #include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -32,299 +30,27 @@
 #include "vssym32.h"
 #include "wine/debug.h"
 
-/* Minimum size of the thumb in pixels */
-#define SCROLL_MIN_THUMB 6
-
-/* Minimum size of the rectangle between the arrows */
-#define SCROLL_MIN_RECT  4
-
-enum SCROLL_HITTEST
-{
-    SCROLL_NOWHERE,      /* Outside the scroll bar */
-    SCROLL_TOP_ARROW,    /* Top or left arrow */
-    SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
-    SCROLL_THUMB,        /* Thumb rectangle */
-    SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
-    SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
-};
-
-static HWND tracking_win = 0;
-static enum SCROLL_HITTEST tracking_hot_part = SCROLL_NOWHERE;
-
 WINE_DEFAULT_DEBUG_CHANNEL(theme_scroll);
 
-static void calc_thumb_dimensions(unsigned int size, SCROLLINFO *si, unsigned int *thumbpos, unsigned int *thumbsize)
+void WINAPI UXTHEME_ScrollBarDraw(HWND hwnd, HDC dc, INT bar, enum SCROLL_HITTEST hit_test,
+                                  const struct SCROLL_TRACKING_INFO *tracking_info,
+                                  BOOL draw_arrows, BOOL draw_interior, RECT *rect, INT arrowsize,
+                                  INT thumbpos, INT thumbsize, BOOL vertical)
 {
-    if (size <= SCROLL_MIN_RECT)
-        *thumbpos = *thumbsize = 0;
-    else if (si->nPage > si->nMax - si->nMin)
-        *thumbpos = *thumbsize = 0;
-    else {
-        if (si->nPage > 0) {
-            *thumbsize = MulDiv(size, si->nPage, si->nMax - si->nMin + 1);
-            if (*thumbsize < SCROLL_MIN_THUMB) *thumbsize = SCROLL_MIN_THUMB;
-        }
-        else *thumbsize = GetSystemMetrics(SM_CXVSCROLL);
-
-        if (size < *thumbsize)
-            *thumbpos = *thumbsize = 0;
-        else {
-            int max = si->nMax - max(si->nPage - 1, 0);
-            size -= *thumbsize;
-            if (si->nMin >= max)
-                *thumbpos = 0;
-            else
-                *thumbpos = MulDiv(size, si->nTrackPos - si->nMin, max - si->nMin);
-        }
-    }
-}
-
-static enum SCROLL_HITTEST hit_test(HWND hwnd, HTHEME theme, POINT pt)
-{
-    RECT r;
-    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
-    BOOL vertical = style & SBS_VERT;
-    SIZE sz;
-    SCROLLINFO si;
-    unsigned int offset, size, upsize, downsize, thumbpos, thumbsize;
-
-    GetWindowRect(hwnd, &r);
-    OffsetRect(&r, -r.left, -r.top);
-
-    if (vertical) {
-        offset = pt.y;
-        size = r.bottom;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_UPNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get up arrow size.\n");
-            upsize = 0;
-        } else
-            upsize = sz.cy;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_DOWNNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get down arrow size.\n");
-            downsize = 0;
-        } else
-            downsize = sz.cy;
-    } else {
-        offset = pt.x;
-        size = r.right;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_LEFTNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get left arrow size.\n");
-            upsize = 0;
-        } else
-            upsize = sz.cx;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_RIGHTNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get right arrow size.\n");
-            downsize = 0;
-        } else
-            downsize = sz.cx;
-    }
-
-    if (pt.x < 0 || pt.x > r.right || pt.y < 0 || pt.y > r.bottom)
-        return SCROLL_NOWHERE;
-
-    if (size < SCROLL_MIN_RECT + upsize + downsize)
-        upsize = downsize = (size - SCROLL_MIN_RECT)/2;
-
-    if (offset < upsize)
-        return SCROLL_TOP_ARROW;
-
-    if (offset > size - downsize)
-        return SCROLL_BOTTOM_ARROW;
-
-    si.cbSize = sizeof(si);
-    si.fMask = SIF_ALL;
-    if (!GetScrollInfo(hwnd, SB_CTL, &si)) {
-        WARN("GetScrollInfo failed.\n");
-        return SCROLL_NOWHERE;
-    }
-
-    calc_thumb_dimensions(size - upsize - downsize, &si, &thumbpos, &thumbsize);
-
-    if (offset < upsize + thumbpos)
-        return SCROLL_TOP_RECT;
-    else if (offset < upsize + thumbpos + thumbsize)
-        return SCROLL_THUMB;
-    else
-        return SCROLL_BOTTOM_RECT;
-}
-
-static void redraw_part(HWND hwnd, HTHEME theme, enum SCROLL_HITTEST part)
-{
-    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
-    BOOL vertical = style & SBS_VERT;
-    SIZE sz;
-    RECT r, partrect;
-    unsigned int size, upsize, downsize;
-
-    if (part == SCROLL_NOWHERE) { /* redraw everything */
-        InvalidateRect(hwnd, NULL, TRUE);
-        return;
-    }
-
-    GetWindowRect(hwnd, &r);
-    OffsetRect(&r, -r.left, -r.top);
-
-    if (vertical) {
-        size = r.bottom;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_UPNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get up arrow size.\n");
-            upsize = 0;
-        } else
-            upsize = sz.cy;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_DOWNNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get down arrow size.\n");
-            downsize = 0;
-        } else
-            downsize = sz.cy;
-    } else {
-        size = r.right;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_LEFTNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get left arrow size.\n");
-            upsize = 0;
-        } else
-            upsize = sz.cx;
-
-        if (FAILED(GetThemePartSize(theme, NULL, SBP_ARROWBTN, ABS_RIGHTNORMAL, NULL, TS_DRAW, &sz))) {
-            WARN("Could not get right arrow size.\n");
-            downsize = 0;
-        } else
-            downsize = sz.cx;
-    }
-
-    if (size < SCROLL_MIN_RECT + upsize + downsize)
-        upsize = downsize = (size - SCROLL_MIN_RECT)/2;
-
-    partrect = r;
-
-    if (part == SCROLL_TOP_ARROW) {
-        if (vertical)
-            partrect.bottom = partrect.top + upsize;
-        else
-            partrect.right = partrect.left + upsize;
-    } else if (part == SCROLL_BOTTOM_ARROW) {
-        if (vertical)
-            partrect.top = partrect.bottom - downsize;
-        else
-            partrect.left = partrect.right - downsize;
-    } else {
-        unsigned int thumbpos, thumbsize;
-        SCROLLINFO si;
-
-        si.cbSize = sizeof(si);
-        si.fMask = SIF_ALL;
-        if (!GetScrollInfo(hwnd, SB_CTL, &si)) {
-            WARN("GetScrollInfo failed.\n");
-            return;
-        }
-
-        calc_thumb_dimensions(size - upsize - downsize, &si, &thumbpos, &thumbsize);
-
-        if (part == SCROLL_TOP_RECT) {
-            if (vertical) {
-                partrect.top = r.top + upsize;
-                partrect.bottom = partrect.top + thumbpos;
-            } else {
-                partrect.left = r.left + upsize;
-                partrect.right = partrect.left + thumbpos;
-            }
-        } else if (part == SCROLL_THUMB) {
-            if (vertical) {
-                partrect.top = r.top + upsize + thumbpos;
-                partrect.bottom = partrect.top + thumbsize;
-            } else {
-                partrect.left = r.left + upsize + thumbpos;
-                partrect.right = partrect.left + thumbsize;
-            }
-        } else if (part == SCROLL_BOTTOM_RECT) {
-            if (vertical) {
-                partrect.top = r.top + upsize + thumbpos + thumbsize;
-                partrect.bottom = r.bottom - downsize;
-            } else {
-                partrect.left = r.left + upsize + thumbpos + thumbsize;
-                partrect.right = r.right - downsize;
-            }
-        }
-    }
-
-    InvalidateRect(hwnd, &partrect, TRUE);
-}
-
-static void scroll_event(HWND hwnd, HTHEME theme, UINT msg, POINT pt)
-{
-    enum SCROLL_HITTEST hittest;
-    TRACKMOUSEEVENT tme;
-
-    if (GetWindowLongW(hwnd, GWL_STYLE) & (SBS_SIZEGRIP | SBS_SIZEBOX))
-        return;
-
-    hittest = hit_test(hwnd, theme, pt);
-
-    switch (msg)
-    {
-        case WM_MOUSEMOVE:
-            hittest = hit_test(hwnd, theme, pt);
-            tracking_win = hwnd;
-            break;
-
-        case WM_MOUSELEAVE:
-            if (tracking_win == hwnd) {
-                hittest = SCROLL_NOWHERE;
-            }
-            break;
-    }
-
-    tme.cbSize = sizeof(tme);
-    tme.dwFlags = TME_QUERY;
-    TrackMouseEvent(&tme);
-
-    if (!(tme.dwFlags & TME_LEAVE) || tme.hwndTrack != hwnd) {
-        tme.dwFlags = TME_LEAVE;
-        tme.hwndTrack = hwnd;
-        TrackMouseEvent(&tme);
-    }
-
-    if (tracking_win != hwnd && msg == WM_MOUSELEAVE) {
-        redraw_part(hwnd, theme, SCROLL_NOWHERE);
-        return;
-    }
-
-    if (tracking_win == hwnd && hittest != tracking_hot_part) {
-        enum SCROLL_HITTEST oldhotpart = tracking_hot_part;
-
-        tracking_hot_part = hittest;
-
-        if (hittest != SCROLL_NOWHERE)
-            redraw_part(hwnd, theme, hittest);
-        else
-            tracking_win = 0;
-
-        if (oldhotpart != SCROLL_NOWHERE)
-            redraw_part(hwnd, theme, oldhotpart);
-    }
-}
-
-static void paint_scrollbar(HWND hwnd, HTHEME theme)
-{
-    HDC dc;
-    PAINTSTRUCT ps;
-    RECT r;
-    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
-    BOOL vertical = style & SBS_VERT;
     BOOL disabled = !IsWindowEnabled(hwnd);
+    HTHEME theme;
+    DWORD style;
 
-    GetWindowRect(hwnd, &r);
-    OffsetRect(&r, -r.left, -r.top);
+    theme = bar == SB_CTL ? GetWindowTheme(hwnd) : OpenThemeData(NULL, WC_SCROLLBARW);
+    if (!theme)
+    {
+        user_api.pScrollBarDraw(hwnd, dc, bar, hit_test, tracking_info, draw_arrows, draw_interior,
+                                rect, arrowsize, thumbpos, thumbsize, vertical);
+        return;
+    }
 
-    dc = BeginPaint(hwnd, &ps);
-
-    if (style & SBS_SIZEBOX || style & SBS_SIZEGRIP) {
+    style = GetWindowLongW(hwnd, GWL_STYLE);
+    if (bar == SB_CTL && (style & SBS_SIZEBOX || style & SBS_SIZEGRIP)) {
         int state;
 
         if (style & SBS_SIZEBOXTOPLEFTALIGN)
@@ -334,20 +60,12 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
 
         if (IsThemeBackgroundPartiallyTransparent(theme, SBP_SIZEBOX, state))
             DrawThemeParentBackground(hwnd, dc, NULL);
-        DrawThemeBackground(theme, dc, SBP_SIZEBOX, state, &r, NULL);
+        DrawThemeBackground(theme, dc, SBP_SIZEBOX, state, rect, NULL);
     } else {
-        SCROLLINFO si;
-        unsigned int thumbpos, thumbsize;
         int uppertrackstate, lowertrackstate, thumbstate;
-        RECT partrect, trackrect;
+        RECT partrect;
         SIZE grippersize;
 
-        si.cbSize = sizeof(si);
-        si.fMask = SIF_ALL;
-        GetScrollInfo(hwnd, SB_CTL, &si);
-
-        trackrect = r;
-
         if (disabled) {
             uppertrackstate = SCRBS_DISABLED;
             lowertrackstate = SCRBS_DISABLED;
@@ -357,20 +75,18 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
             lowertrackstate = SCRBS_NORMAL;
             thumbstate = SCRBS_NORMAL;
 
-            if (tracking_win == hwnd) {
-                if (tracking_hot_part == SCROLL_TOP_RECT)
-                    uppertrackstate = SCRBS_HOT;
-                else if (tracking_hot_part == SCROLL_BOTTOM_RECT)
-                    lowertrackstate = SCRBS_HOT;
-                else if (tracking_hot_part == SCROLL_THUMB)
-                    thumbstate = SCRBS_HOT;
-            }
+            if (hit_test == SCROLL_TOP_RECT)
+                uppertrackstate = SCRBS_HOT;
+            else if (hit_test == SCROLL_BOTTOM_RECT)
+                lowertrackstate = SCRBS_HOT;
+            else if (hit_test == SCROLL_THUMB)
+                thumbstate = SCRBS_HOT;
         }
 
-        DrawThemeParentBackground(hwnd, dc, NULL);
+        if (bar == SB_CTL)
+            DrawThemeParentBackground(hwnd, dc, NULL);
 
         if (vertical) {
-            SIZE upsize, downsize;
             int uparrowstate, downarrowstate;
 
             if (disabled) {
@@ -380,50 +96,29 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
                 uparrowstate = ABS_UPNORMAL;
                 downarrowstate = ABS_DOWNNORMAL;
 
-                if (tracking_win == hwnd) {
-                    if (tracking_hot_part == SCROLL_TOP_ARROW)
-                        uparrowstate = ABS_UPHOT;
-                    else if (tracking_hot_part == SCROLL_BOTTOM_ARROW)
-                        downarrowstate = ABS_DOWNHOT;
-                }
+                if (hit_test == SCROLL_TOP_ARROW)
+                    uparrowstate = ABS_UPHOT;
+                else if (hit_test == SCROLL_BOTTOM_ARROW)
+                    downarrowstate = ABS_DOWNHOT;
             }
 
-            if (FAILED(GetThemePartSize(theme, dc, SBP_ARROWBTN, uparrowstate, NULL, TS_DRAW, &upsize))) {
-                WARN("Could not get up arrow size.\n");
-                return;
-            }
-
-            if (FAILED(GetThemePartSize(theme, dc, SBP_ARROWBTN, downarrowstate, NULL, TS_DRAW, &downsize))) {
-                WARN("Could not get down arrow size.\n");
-                return;
-            }
-
-            if (r.bottom - r.top - upsize.cy - downsize.cy < SCROLL_MIN_RECT)
-                upsize.cy = downsize.cy = (r.bottom - r.top - SCROLL_MIN_RECT)/2;
-
-            partrect = r;
-            partrect.bottom = partrect.top + upsize.cy;
+            partrect = *rect;
+            partrect.bottom = partrect.top + arrowsize;
             DrawThemeBackground(theme, dc, SBP_ARROWBTN, uparrowstate, &partrect, NULL);
 
-            trackrect.top = partrect.bottom;
-
-            partrect.bottom = r.bottom;
-            partrect.top = partrect.bottom - downsize.cy;
+            partrect.bottom = rect->bottom;
+            partrect.top = partrect.bottom - arrowsize;
             DrawThemeBackground(theme, dc, SBP_ARROWBTN, downarrowstate, &partrect, NULL);
 
-            trackrect.bottom = partrect.top;
-
-            calc_thumb_dimensions(trackrect.bottom - trackrect.top, &si, &thumbpos, &thumbsize);
-
             if (thumbpos > 0) {
-                partrect.top = trackrect.top;
-                partrect.bottom = partrect.top + thumbpos;
+                partrect.top = rect->top + arrowsize;
+                partrect.bottom = rect->top + thumbpos;
 
                 DrawThemeBackground(theme, dc, SBP_UPPERTRACKVERT, uppertrackstate, &partrect, NULL);
             }
 
             if (thumbsize > 0) {
-                partrect.top = trackrect.top + thumbpos;
+                partrect.top = rect->top + thumbpos;
                 partrect.bottom = partrect.top + thumbsize;
 
                 DrawThemeBackground(theme, dc, SBP_THUMBBTNVERT, thumbstate, &partrect, NULL);
@@ -438,14 +133,14 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
                 }
             }
 
-            if (thumbpos + thumbsize < trackrect.bottom - trackrect.top) {
-                partrect.bottom = trackrect.bottom;
-                partrect.top = trackrect.top + thumbsize + thumbpos;
-
+            partrect.bottom = rect->bottom - arrowsize;
+            if (thumbsize > 0)
+                partrect.top = rect->top + thumbpos + thumbsize;
+            else
+                partrect.top = rect->top + arrowsize;
+            if (partrect.bottom > partrect.top)
                 DrawThemeBackground(theme, dc, SBP_LOWERTRACKVERT, lowertrackstate, &partrect, NULL);
-            }
         } else {
-            SIZE leftsize, rightsize;
             int leftarrowstate, rightarrowstate;
 
             if (disabled) {
@@ -455,50 +150,29 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
                 leftarrowstate = ABS_LEFTNORMAL;
                 rightarrowstate = ABS_RIGHTNORMAL;
 
-                if (tracking_win == hwnd) {
-                    if (tracking_hot_part == SCROLL_TOP_ARROW)
-                        leftarrowstate = ABS_LEFTHOT;
-                    else if (tracking_hot_part == SCROLL_BOTTOM_ARROW)
-                        rightarrowstate = ABS_RIGHTHOT;
-                }
+                if (hit_test == SCROLL_TOP_ARROW)
+                    leftarrowstate = ABS_LEFTHOT;
+                else if (hit_test == SCROLL_BOTTOM_ARROW)
+                    rightarrowstate = ABS_RIGHTHOT;
             }
 
-            if (FAILED(GetThemePartSize(theme, dc, SBP_ARROWBTN, leftarrowstate, NULL, TS_DRAW, &leftsize))) {
-                WARN("Could not get left arrow size.\n");
-                return;
-            }
-
-            if (FAILED(GetThemePartSize(theme, dc, SBP_ARROWBTN, rightarrowstate, NULL, TS_DRAW, &rightsize))) {
-                WARN("Could not get right arrow size.\n");
-                return;
-            }
-
-            if (r.right - r.left - leftsize.cx - rightsize.cx < SCROLL_MIN_RECT)
-                leftsize.cx = rightsize.cx = (r.right - r.left - SCROLL_MIN_RECT)/2;
-
-            partrect = r;
-            partrect.right = partrect.left + leftsize.cx;
+            partrect = *rect;
+            partrect.right = partrect.left + arrowsize;
             DrawThemeBackground(theme, dc, SBP_ARROWBTN, leftarrowstate, &partrect, NULL);
 
-            trackrect.left = partrect.right;
-
-            partrect.right = r.right;
-            partrect.left = partrect.right - rightsize.cx;
+            partrect.right = rect->right;
+            partrect.left = partrect.right - arrowsize;
             DrawThemeBackground(theme, dc, SBP_ARROWBTN, rightarrowstate, &partrect, NULL);
 
-            trackrect.right = partrect.left;
-
-            calc_thumb_dimensions(trackrect.right - trackrect.left, &si, &thumbpos, &thumbsize);
-
             if (thumbpos > 0) {
-                partrect.left = trackrect.left;
-                partrect.right = partrect.left + thumbpos;
+                partrect.left = rect->left + arrowsize;
+                partrect.right = rect->left + thumbpos;
 
                 DrawThemeBackground(theme, dc, SBP_UPPERTRACKHORZ, uppertrackstate, &partrect, NULL);
             }
 
             if (thumbsize > 0) {
-                partrect.left = trackrect.left + thumbpos;
+                partrect.left = rect->left + thumbpos;
                 partrect.right = partrect.left + thumbsize;
 
                 DrawThemeBackground(theme, dc, SBP_THUMBBTNHORZ, thumbstate, &partrect, NULL);
@@ -513,16 +187,18 @@ static void paint_scrollbar(HWND hwnd, HTHEME theme)
                 }
             }
 
-            if (thumbpos + thumbsize < trackrect.right - trackrect.left) {
-                partrect.right = trackrect.right;
-                partrect.left = trackrect.left + thumbsize + thumbpos;
-
+            partrect.right = rect->right - arrowsize;
+            if (thumbsize > 0)
+                partrect.left = rect->left + thumbpos + thumbsize;
+            else
+                partrect.left = rect->left + arrowsize;
+            if (partrect.right > partrect.left)
                 DrawThemeBackground(theme, dc, SBP_LOWERTRACKHORZ, lowertrackstate, &partrect, NULL);
-            }
         }
     }
 
-    EndPaint(hwnd, &ps);
+    if (bar != SB_CTL)
+        CloseThemeData(theme);
 }
 
 LRESULT WINAPI UXTHEME_ScrollbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
@@ -531,7 +207,6 @@ LRESULT WINAPI UXTHEME_ScrollbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
     const WCHAR* themeClass = WC_SCROLLBARW;
     HTHEME theme;
     LRESULT result;
-    POINT pt;
 
     TRACE("(%p, 0x%x, %lu, %lu, %d)\n", hwnd, msg, wParam, lParam, unicode);
 
@@ -560,23 +235,6 @@ LRESULT WINAPI UXTHEME_ScrollbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
              * which will do the repaint. */
             break;
 
-        case WM_PAINT:
-            theme = GetWindowTheme(hwnd);
-            if (!theme) return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
-
-            paint_scrollbar(hwnd, theme);
-            break;
-
-        case WM_MOUSEMOVE:
-        case WM_MOUSELEAVE:
-            theme = GetWindowTheme(hwnd);
-            if (!theme) return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
-
-            pt.x = (short)LOWORD(lParam);
-            pt.y = (short)HIWORD(lParam);
-            scroll_event(hwnd, theme, msg, pt);
-            break;
-
         default:
             return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
     }
diff --git a/dlls/uxtheme/system.c b/dlls/uxtheme/system.c
index f5ddc20eb08..63861260de9 100644
--- a/dlls/uxtheme/system.c
+++ b/dlls/uxtheme/system.c
@@ -1230,6 +1230,7 @@ BOOL WINAPI ThemeHooksInstall(void)
     struct user_api_hook hooks;
 
     hooks.pDefDlgProc = UXTHEME_DefDlgProc;
+    hooks.pScrollBarDraw = UXTHEME_ScrollBarDraw;
     hooks.pScrollBarWndProc = UXTHEME_ScrollbarWndProc;
     return __wine_register_user_api_hook(&hooks, &user_api);
 }
diff --git a/dlls/uxtheme/uxthemedll.h b/dlls/uxtheme/uxthemedll.h
index 67932f22f88..4b8f95764d6 100644
--- a/dlls/uxtheme/uxthemedll.h
+++ b/dlls/uxtheme/uxthemedll.h
@@ -103,6 +103,10 @@ extern void UXTHEME_UninitSystem(void) DECLSPEC_HIDDEN;
 
 extern struct user_api_hook user_api DECLSPEC_HIDDEN;
 LRESULT WINAPI UXTHEME_DefDlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode) DECLSPEC_HIDDEN;
+void WINAPI UXTHEME_ScrollBarDraw(HWND hwnd, HDC dc, INT bar, enum SCROLL_HITTEST hit_test,
+                                  const struct SCROLL_TRACKING_INFO *tracking_info,
+                                  BOOL draw_arrows, BOOL draw_interior, RECT *rect, INT arrowsize,
+                                  INT thumbpos, INT thumbsize, BOOL vertical) DECLSPEC_HIDDEN;
 LRESULT WINAPI UXTHEME_ScrollbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
                                         BOOL unicode) DECLSPEC_HIDDEN;
 
diff --git a/include/winuser.h b/include/winuser.h
index 6df5ead5bc5..497cfc7782e 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -4409,9 +4409,35 @@ WORD        WINAPI SYSTEM_KillSystemTimer( WORD );
 WINUSERAPI BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput );
 
 /* Uxtheme hook functions and struct */
+
+/* Scroll bar hit testing */
+enum SCROLL_HITTEST
+{
+    SCROLL_NOWHERE,      /* Outside the scroll bar */
+    SCROLL_TOP_ARROW,    /* Top or left arrow */
+    SCROLL_TOP_RECT,     /* Rectangle between the top arrow and the thumb */
+    SCROLL_THUMB,        /* Thumb rectangle */
+    SCROLL_BOTTOM_RECT,  /* Rectangle between the thumb and the bottom arrow */
+    SCROLL_BOTTOM_ARROW  /* Bottom or right arrow */
+};
+
+/* Scroll bar tracking information */
+struct SCROLL_TRACKING_INFO
+{
+    HWND win;                       /* Tracking window */
+    INT bar;                        /* SB_HORZ/SB_VERT/SB_CTL */
+    INT thumb_pos;                  /* Thumb position */
+    INT thumb_val;                  /* Current thumb value from thumb position */
+    BOOL vertical;                  /* Is scroll bar vertical */
+    enum SCROLL_HITTEST hit_test;   /* Hit Test code of the last button-down event */
+};
+
 struct user_api_hook
 {
     LRESULT (WINAPI *pDefDlgProc)(HWND, UINT, WPARAM, LPARAM, BOOL);
+    void (WINAPI *pScrollBarDraw)(HWND, HDC, INT, enum SCROLL_HITTEST,
+                                  const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, INT, INT,
+                                  INT, BOOL);
     LRESULT (WINAPI *pScrollBarWndProc)(HWND, UINT, WPARAM, LPARAM, BOOL);
 };
 
-- 
2.30.2




More information about the wine-devel mailing list