Avoid infinite repaint loop in wxListCtrl with wxLC_HRULES

A virtual wxListCtrl with wxLC_HRULES which wasn't fully visible on
screen, i.e. didn't fit into the visible area of its parent window
(which included the case when the parent was a wxScrolledWindow, for
which it is normal and expected not to be able to fit all of its
children) got into an infinite repaint loop because of a RefreshRect()
call inside wxListCtrl::OnPaint().

Fix this by avoiding to call RefreshRect() added in 374db28747 (Fix
wxMSW ListCtrl drawing of horizontal rules for new items, 2016-05-04),
unless the current clipping rectangle is less than the actually
effective visible width and not the full client width, which can be much
bigger.

This still doesn't ensure that we don't enter into an infinite recursion
here, so it would be even better to call RefreshRect() at most once
before the next control change, but it's not clear when exactly this
"already refreshed" flag would need to be reset.

See #17158.

Closes #18850.
This commit is contained in:
Vadim Zeitlin
2020-07-24 01:32:44 +02:00
parent 6f968105b5
commit bb3177dd3b

View File

@@ -3278,7 +3278,13 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
dc.SetPen(pen);
dc.SetBrush(* wxTRANSPARENT_BRUSH);
wxSize clientSize = GetClientSize();
// Find the coordinate of the right most visible point: this is not the
// same as GetClientSize().x because the window might not be fully visible,
// it could be clipped by its parent.
const wxSize size = GetSize();
const int availableWidth = GetParent()->GetClientSize().x - GetPosition().x;
int visibleWidth = wxMin(GetClientSize().x,
availableWidth - GetWindowBorderSize().x);
const int countPerPage = GetCountPerPage();
if (countPerPage < 0)
@@ -3312,10 +3318,10 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
list control. In that case we request for the part to the right of
the rightmost column to be drawn as well.
*/
if ( clipRect.GetRight() != clientSize.x - 1 && clipRect.width )
if ( clipRect.GetRight() < visibleWidth - 1 && clipRect.width )
{
RefreshRect(wxRect(clipRect.GetRight(), clipRect.y,
clientSize.x - clipRect.width, clipRect.height),
visibleWidth - clipRect.width, clipRect.height),
false /* don't erase background */);
}
}
@@ -3359,7 +3365,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
wxDCBrushChanger changeBrush(dc, GetBackgroundColour());
dc.DrawRectangle(0, topItemRect.GetY() - gap,
clientSize.GetWidth(), gap);
visibleWidth, gap);
}
const int numCols = GetColumnCount();