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

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Jun 5 06:38:57 CDT 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. But we have to limit
the amount of scrolling in this case to avoid "jumping over" columns,
if the window is too small. This matches Windows behavior.

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. 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 and didn't help with overflow either, because the line that
assigns to descr->wheel_remain operates on integers, so if it overflowed
in the initial float operation, it would overflow on this line anyway.

In other words, the current code didn't protect from overflow, so we can
simply get rid of the float cast (WHEEL_DELTA is too small for overflow to
be a concern, though).

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

diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index 8fd556c..991baac 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -2068,7 +2068,7 @@ 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 = 3;
 
     SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
 
@@ -2082,9 +2082,20 @@ 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;
+        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 -= (WHEEL_DELTA * cLineScroll) / pulScrollLines;
+            cLineScroll *= descr->page_size;
+        }
+        else
+        {
+            pulScrollLines = min((UINT)descr->page_size, pulScrollLines);
+            cLineScroll = (pulScrollLines * descr->wheel_remain) / WHEEL_DELTA;
+            descr->wheel_remain -= (WHEEL_DELTA * cLineScroll) / pulScrollLines;
+        }
         LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE );
     }
     return 0;
-- 
2.21.0




More information about the wine-devel mailing list