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

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Mar 6 07:42:53 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. 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. Some casts have
been removed by making variables signed (with an unsigned tmp since
SystemParametersInfoW expects UINT), 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 and didn't help with overflow
either, as initially assumed.

As you can see, it gets assigned to cLineScroll (which is integer) and then
gets multiplied as an *integer* back by WHEEL_DELTA, so if the float were
to help with overflow before the division, it would overflow on the next
line anyway since you apply the multiply back (but as an integer)...

Anyway, overflow is extremely unlikely (and probably impossible in practice)
since WHEEL_DELTA is just 120, and it was already vulnerable to overflow
currently.

 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 bd9cffd..2f4d4fe 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -2068,9 +2068,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) ||
@@ -2081,10 +2083,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.20.1




More information about the wine-devel mailing list