[PATCH 5/7] win32u: Move scroll bar WM_SETFOCUS and WM_KILLFOCUS implementation from user32.

Jacek Caban wine at gitlab.winehq.org
Mon Jul 4 07:05:56 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

---
 dlls/user32/scroll.c         |  39 ---------
 dlls/win32u/ntgdi_private.h  |   1 -
 dlls/win32u/scroll.c         | 158 +++++++++++++++++++++++++++++++++++
 dlls/win32u/win32u_private.h |   1 +
 4 files changed, 159 insertions(+), 40 deletions(-)

diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c
index cc847b48ec6..01f7f3b88ae 100644
--- a/dlls/user32/scroll.c
+++ b/dlls/user32/scroll.c
@@ -1385,46 +1385,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA
         break;
 
     case WM_SETFOCUS:
-        {
-            /* Create a caret when a ScrollBar get focus */
-            RECT rect;
-            int arrowSize, thumbSize, thumbPos, vertical;
-            vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,
-                                                &arrowSize, &thumbSize, &thumbPos );
-            if (!vertical)
-            {
-                NtUserCreateCaret( hwnd, (HBITMAP)1, thumbSize - 2, rect.bottom - rect.top - 2 );
-                SetCaretPos(thumbPos+1, rect.top+1);
-            }
-            else
-            {
-                NtUserCreateCaret( hwnd, (HBITMAP)1, rect.right - rect.left - 2, thumbSize - 2);
-                SetCaretPos(rect.top+1, thumbPos+1);
-            }
-            NtUserShowCaret( hwnd );
-        }
-        break;
-
     case WM_KILLFOCUS:
-        {
-            RECT rect;
-            int arrowSize, thumbSize, thumbPos, vertical;
-            vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,&arrowSize, &thumbSize, &thumbPos );
-            if (!vertical){
-                rect.left=thumbPos+1;
-                rect.right=rect.left+thumbSize;
-            }
-            else
-            {
-                rect.top=thumbPos+1;
-                rect.bottom=rect.top+thumbSize;
-            }
-            NtUserHideCaret( hwnd );
-            NtUserInvalidateRect( hwnd, &rect, 0 );
-            DestroyCaret();
-        }
-        break;
-
     case WM_CREATE:
     case WM_ERASEBKGND:
     case WM_GETDLGCODE:
diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h
index ac552897769..0397138b109 100644
--- a/dlls/win32u/ntgdi_private.h
+++ b/dlls/win32u/ntgdi_private.h
@@ -391,7 +391,6 @@ extern void lp_to_dp( DC *dc, POINT *points, INT count ) DECLSPEC_HIDDEN;
 extern BOOL set_map_mode( DC *dc, int mode ) DECLSPEC_HIDDEN;
 extern void combine_transform( XFORM *result, const XFORM *xform1,
                                const XFORM *xform2 ) DECLSPEC_HIDDEN;
-extern int muldiv( int a, int b, int c ) DECLSPEC_HIDDEN;
 
 /* driver.c */
 extern BOOL is_display_device( LPCWSTR name ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/scroll.c b/dlls/win32u/scroll.c
index a15c8bfd36d..14bec1e3b83 100644
--- a/dlls/win32u/scroll.c
+++ b/dlls/win32u/scroll.c
@@ -32,6 +32,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(scroll);
 
 #define SCROLLBAR_MAGIC 0x5c6011ba
 
+/* Minimum size of the rectangle between the arrows */
+#define SCROLL_MIN_RECT  4
+
+/* Minimum size of the thumb in pixels */
+#define SCROLL_MIN_THUMB 8
+
+/* Overlap between arrows and thumb */
+#define SCROLL_ARROW_THUMB_OVERLAP 0
+
 static struct scroll_info *get_scroll_info_ptr( HWND hwnd, int bar, BOOL alloc )
 {
     struct scroll_info *ret = NULL;
@@ -84,6 +93,113 @@ static BOOL show_scroll_bar( HWND hwnd, int bar, BOOL show_horz, BOOL show_vert
     return FALSE; /* no frame changes */
 }
 
+/***********************************************************************
+ *           get_scroll_bar_rect
+ *
+ * Compute the scroll bar rectangle, in drawing coordinates (i.e. client
+ * coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
+ * 'arrow_size' returns the width or height of an arrow (depending on
+ * the orientation of the scrollbar), 'thumb_size' returns the size of
+ * the thumb, and 'thumb_pos' returns the position of the thumb
+ * relative to the left or to the top.
+ * Return TRUE if the scrollbar is vertical, FALSE if horizontal.
+ */
+static BOOL get_scroll_bar_rect( HWND hwnd, int bar, RECT *rect, int *arrow_size,
+                                 int *thumb_size, int *thumb_pos )
+{
+    int pixels, min_thumb_size;
+    BOOL vertical;
+    WND *win = get_win_ptr( hwnd );
+
+    if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE;
+
+    switch(bar)
+    {
+    case SB_HORZ:
+        get_window_rects( hwnd, COORDS_WINDOW, NULL, rect, get_thread_dpi() );
+        rect->top = rect->bottom;
+        rect->bottom += get_system_metrics( SM_CYHSCROLL );
+        if (win->dwStyle & WS_VSCROLL) rect->right++;
+        vertical = FALSE;
+        break;
+
+    case SB_VERT:
+        get_window_rects( hwnd, COORDS_WINDOW, NULL, rect, get_thread_dpi() );
+        if (win->dwExStyle & WS_EX_LEFTSCROLLBAR)
+        {
+            rect->right = rect->left;
+            rect->left -= get_system_metrics( SM_CXVSCROLL );
+        }
+        else
+        {
+            rect->left = rect->right;
+            rect->right += get_system_metrics( SM_CXVSCROLL );
+        }
+        if (win->dwStyle & WS_HSCROLL) rect->bottom++;
+        vertical = TRUE;
+        break;
+
+    case SB_CTL:
+        get_client_rect( hwnd, rect );
+        vertical = (win->dwStyle & SBS_VERT) != 0;
+        break;
+
+    default:
+        release_win_ptr( win );
+        return FALSE;
+    }
+
+    if (vertical) pixels = rect->bottom - rect->top;
+    else pixels = rect->right - rect->left;
+
+    if (pixels <= 2 * get_system_metrics( SM_CXVSCROLL ) + SCROLL_MIN_RECT)
+    {
+        if (pixels > SCROLL_MIN_RECT)
+            *arrow_size = (pixels - SCROLL_MIN_RECT) / 2;
+        else
+            *arrow_size = 0;
+        *thumb_pos = *thumb_size = 0;
+    }
+    else
+    {
+        struct scroll_info *info = get_scroll_info_ptr( hwnd, bar, TRUE );
+        if (!info)
+        {
+            WARN( "called for missing scroll bar\n" );
+            release_win_ptr( win );
+            return FALSE;
+        }
+        *arrow_size = get_system_metrics( SM_CXVSCROLL );
+        pixels -= 2 * (get_system_metrics( SM_CXVSCROLL ) - SCROLL_ARROW_THUMB_OVERLAP);
+
+        if (info->page)
+        {
+            *thumb_size = muldiv( pixels,info->page, info->maxVal - info->minVal + 1 );
+            min_thumb_size = muldiv( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ), 96 );
+            if (*thumb_size < min_thumb_size) *thumb_size = min_thumb_size;
+        }
+        else *thumb_size = get_system_metrics( SM_CXVSCROLL );
+
+        if ((pixels -= *thumb_size ) < 0 || (info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
+        {
+            /* Rectangle too small or scrollbar disabled -> no thumb */
+            *thumb_pos = *thumb_size = 0;
+        }
+        else
+        {
+            int max = info->maxVal - max( info->page-1, 0 );
+            if (info->minVal >= max)
+                *thumb_pos = *arrow_size - SCROLL_ARROW_THUMB_OVERLAP;
+            else
+                *thumb_pos = *arrow_size - SCROLL_ARROW_THUMB_OVERLAP
+                    + muldiv( pixels, info->curVal - info->minVal, max - info->minVal );
+        }
+        release_scroll_info_ptr( info );
+    }
+    release_win_ptr( win );
+    return vertical;
+}
+
 static void create_scroll_bar( HWND hwnd, CREATESTRUCTW *create )
 {
     struct scroll_info *info = NULL;
@@ -148,6 +264,48 @@ LRESULT scroll_bar_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
         create_scroll_bar( hwnd, (CREATESTRUCTW *)lparam );
         return 0;
 
+    case WM_SETFOCUS:
+        {
+            /* Create a caret when a ScrollBar get focus */
+            RECT rect;
+            int arrow_size, thumb_size, thumb_pos, vertical;
+            vertical = get_scroll_bar_rect( hwnd, SB_CTL, &rect, &arrow_size,
+                                            &thumb_size, &thumb_pos );
+            if (!vertical)
+            {
+                NtUserCreateCaret( hwnd, (HBITMAP)1, thumb_size - 2, rect.bottom - rect.top - 2 );
+                set_caret_pos( thumb_pos + 1, rect.top + 1 );
+            }
+            else
+            {
+                NtUserCreateCaret( hwnd, (HBITMAP)1, rect.right - rect.left - 2, thumb_size - 2 );
+                set_caret_pos( rect.top + 1, thumb_pos + 1 );
+            }
+            NtUserShowCaret( hwnd );
+        }
+        return 0;
+
+    case WM_KILLFOCUS:
+        {
+            int arrow_size, thumb_size, thumb_pos, vertical;
+            RECT rect;
+            vertical = get_scroll_bar_rect( hwnd, SB_CTL, &rect,&arrow_size, &thumb_size, &thumb_pos );
+            if (!vertical)
+            {
+                rect.left = thumb_pos + 1;
+                rect.right = rect.left + thumb_size;
+            }
+            else
+            {
+                rect.top = thumb_pos + 1;
+                rect.bottom = rect.top + thumb_size;
+            }
+            NtUserHideCaret( hwnd );
+            NtUserInvalidateRect( hwnd, &rect, 0 );
+            destroy_caret();
+        }
+        return 0;
+
     case WM_ERASEBKGND:
         return 1;
 
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 684a5e59c5b..49c81ea3bef 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -535,6 +535,7 @@ extern NTSTATUS gdi_init(void) DECLSPEC_HIDDEN;
 extern NTSTATUS callbacks_init( void *args ) DECLSPEC_HIDDEN;
 extern void winstation_init(void) DECLSPEC_HIDDEN;
 extern void sysparams_init(void) DECLSPEC_HIDDEN;
+extern int muldiv( int a, int b, int c ) DECLSPEC_HIDDEN;
 
 extern HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len,
                             DWORD options, DWORD *disposition ) DECLSPEC_HIDDEN;
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/368



More information about the wine-devel mailing list