[Bug 59655] New: comctl32: Infinite WM_PAINT loop in SysListView32 when parent triggers layout update during NM_CUSTOMDRAW (MPC-BE)
http://bugs.winehq.org/show_bug.cgi?id=59655 Bug ID: 59655 Summary: comctl32: Infinite WM_PAINT loop in SysListView32 when parent triggers layout update during NM_CUSTOMDRAW (MPC-BE) Product: Wine Version: 11.6 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: major Priority: P2 Component: comctl32 Assignee: wine-bugs@list.winehq.org Reporter: lldmakhbfcrmqyluns@nesopf.com Distribution: --- Steps to reproduce: Open MPC-BE. Ensure the Playlist panel is visible (View -> Playlist). Click on the top of the playlist window. The application GUI freezes permanently. Analysis / Root Cause: By adding extensive custom tracing to dlls/comctl32/listview.c, an infinite WM_PAINT loop was identified. Here is what happens during a single iteration of the loop: WM_PAINT is dispatched, calling LISTVIEW_Refresh. LISTVIEW_Refresh sets infoPtr->bIsDrawing = TRUE and starts drawing. During the drawing process, the listview sends NM_CUSTOMDRAW (stage CDDS_PREPAINT / CDDS_ITEMPREPAINT) to the parent window (MPC-BE). The parent's custom draw handler executes logic that indirectly triggers a layout update of the listview (e.g., via SetWindowPos on the header or changing item metrics). This layout update calls LISTVIEW_UpdateSize, which eventually calls LISTVIEW_InvalidateList. LISTVIEW_InvalidateList calls LISTVIEW_InvalidateRect(infoPtr, NULL), marking the entire client area as dirty. LISTVIEW_Refresh finishes and sets infoPtr->bIsDrawing = FALSE. Because the client area was invalidated during step 6, the system immediately generates a new WM_PAINT message. The cycle repeats indefinitely. Native Windows does not freeze, suggesting it ignores invalidation requests while the control is already actively painting itself. The Fix: The LISTVIEW_INFO structure already contains the bIsDrawing flag specifically to prevent reentrancy issues. The fix is to simply return early from LISTVIEW_InvalidateList if bIsDrawing is TRUE. Since LISTVIEW_Refresh is currently repainting the entire visible area anyway, queuing another full invalidation is both redundant and dangerous. Patch / Diff diff --- a/dlls/comctl32/listview.c +++ b/dlls/comctl32/listview.c @@ -1792,6 +1792,7 @@ static inline void LISTVIEW_InvalidateList(const LISTVIEW_INFO *infoPtr) { + if (infoPtr->bIsDrawing) return; LISTVIEW_InvalidateRect(infoPtr, NULL); } -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59655 --- Comment #1 from T_Im <lldmakhbfcrmqyluns@nesopf.com> --- FYI: I'm not a C dev and don't plan to submit a formal patch. I'm just sharing analysis to help fix the bug for everyone. Feel free to use or rewrite the code. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59655 --- Comment #2 from T_Im <lldmakhbfcrmqyluns@nesopf.com> --- Added Stefan Dösinger and Zhiyi Zhang to CC as recent contributors to these files. -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
http://bugs.winehq.org/show_bug.cgi?id=59655 T_Im <lldmakhbfcrmqyluns@nesopf.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |stefan@codeweavers.com, | |zzhang@codeweavers.com -- Do not reply to this email, post in Bugzilla using the above URL to reply. You are receiving this mail because: You are watching all bug changes.
participants (1)
-
WineHQ Bugzilla