[PATCH 1/6] comctl32/listbox: Handle Mouse Wheel scrolling for multi-column listboxes properly

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Feb 4 07:19:38 CST 2019


Multi-column listboxes scroll horizontally, so each wheel tick must go an
entire page at a time instead of an item at a time.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=22253
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

These notes apply to all the patches in the series. Temporary variable has
been used to get rid of many casts, as suggested.

The calculation has been simplified to just integer arithmetic in all
cases, since the division (the only operation with a fractional result)
was immediately truncated to integer anyway.

Note that the float doesn't help with overflow either. As you can see, it
gets assigned to cLineScroll (which is integer) and then gets multiplied
back by WHEEL_DELTA, so if the float were to help with overflow in the
first place, it would overflow on the next line regardless.

Anyway, overflow is probably impossible in practice since WHEEL_DELTA is
just 120, but even if so, it was already overflowing with float, so there's
no reason to have that cast...

 dlls/comctl32/listbox.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index cb645b4..9f56a2f 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -2012,9 +2012,11 @@ static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD scrollReq, WORD pos
 
 static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
 {
-    UINT pulScrollLines = 3;
+    INT pulScrollLines;
+    UINT tmp = 3;
 
-    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
+    SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &tmp, 0);
+    pulScrollLines = tmp;
 
     /* if scrolling changes direction, ignore left overs */
     if ((delta < 0 && descr->wheel_remain < 0) ||
@@ -2025,10 +2027,21 @@ static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
 
     if (descr->wheel_remain && pulScrollLines)
     {
-        int cLineScroll;
-        pulScrollLines = min((UINT) descr->page_size, pulScrollLines);
-        cLineScroll = pulScrollLines * (float)descr->wheel_remain / WHEEL_DELTA;
-        descr->wheel_remain -= WHEEL_DELTA * cLineScroll / (int)pulScrollLines;
+        INT cLineScroll;
+        if (descr->style & LBS_MULTICOLUMN)
+        {
+            pulScrollLines = min((UINT)descr->width / descr->column_width, pulScrollLines);
+            pulScrollLines = max(1U, pulScrollLines);
+            cLineScroll = (pulScrollLines * descr->wheel_remain) / WHEEL_DELTA;
+            descr->wheel_remain -= (cLineScroll * WHEEL_DELTA) / pulScrollLines;
+            cLineScroll *= descr->page_size;
+        }
+        else
+        {
+            pulScrollLines = min((UINT)descr->page_size, pulScrollLines);
+            cLineScroll = (pulScrollLines * descr->wheel_remain) / WHEEL_DELTA;
+            descr->wheel_remain -= (cLineScroll * WHEEL_DELTA) / pulScrollLines;
+        }
         LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE );
     }
     return 0;
-- 
2.19.1




More information about the wine-devel mailing list