From 0ec0518993731403e52f7703be03e6b452f8c8a5 Mon Sep 17 00:00:00 2001 From: paulcor Date: Sat, 20 Jun 2026 10:48:01 -0700 Subject: [PATCH] Avoid using very large wxDC origin offsets with wxGenericListCtrl Using the wxDC origin to implement scrolled drawing can require very large origin offsets, which can exceed Cairo coordinate limits (2^23), and therefore currently wxGTK3 limits as well. Managing the scroll offsets turns out to be pretty simple in this case, avoiding any coordinate limitations. See #25365 --- include/wx/generic/private/listctrl.h | 3 +- src/generic/listctrl.cpp | 67 +++++++++++++-------------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index aaa36ad5c5..a758259b1a 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -275,13 +275,12 @@ public: } // draw the line on the given DC in icon/list mode - void Draw( wxDC *dc, bool current ); + void Draw( wxDC *dc, const wxPoint& origin, bool current ); // the same in report mode: it needs more parameters as we don't store // everything in the item in report mode void DrawInReportMode( wxDC *dc, const wxRect& rect, - const wxRect& rectHL, bool highlighted, bool current, bool checked ); diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index a277f8568a..fbf28b9472 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -708,11 +708,14 @@ void wxListLineData::ApplyAttributes(wxDC *dc, #endif } -void wxListLineData::Draw(wxDC *dc, bool current) +void wxListLineData::Draw(wxDC *dc, const wxPoint& origin, bool current) { wxCHECK_RET( !m_items.empty(), wxT("no subitems at all??") ); - ApplyAttributes(dc, m_gi->m_rectHighlight, IsHighlighted(), current); + wxRect rect(m_gi->m_rectHighlight); + rect.Offset(origin); + + ApplyAttributes(dc, rect, IsHighlighted(), current); wxListItemData* const item = &m_items[0]; if (item->HasImage()) @@ -720,13 +723,14 @@ void wxListLineData::Draw(wxDC *dc, bool current) // centre the image inside our rectangle, this looks nicer when items // ae aligned in a row const wxRect& rectIcon = m_gi->m_rectIcon; - - m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y); + m_owner->DrawImage( + item->GetImage(), dc, rectIcon.x + origin.x, rectIcon.y + origin.y); } if (item->HasText()) { - const wxRect& rectLabel = m_gi->m_rectLabel; + wxRect rectLabel = m_gi->m_rectLabel; + rectLabel.Offset(origin); wxDCClipper clipper(*dc, rectLabel); dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y); @@ -735,7 +739,6 @@ void wxListLineData::Draw(wxDC *dc, bool current) void wxListLineData::DrawInReportMode( wxDC *dc, const wxRect& rect, - const wxRect& rectHL, bool highlighted, bool current, bool checked ) @@ -746,7 +749,7 @@ void wxListLineData::DrawInReportMode( wxDC *dc, // Note: GetSubItemRect() needs to be modified if the layout here changes. - ApplyAttributes(dc, rectHL, highlighted, current); + ApplyAttributes(dc, rect, highlighted, current); wxCoord x = rect.x; wxCoord yMid = rect.y + rect.height/2; @@ -2048,10 +2051,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) return; } - GetListCtrl()->PrepareDC( dc ); - - int dev_x, dev_y; - GetListCtrl()->CalcScrolledPosition( 0, 0, &dev_x, &dev_y ); + const wxPoint origin(GetListCtrl()->CalcScrolledPosition(wxPoint(0, 0))); if ( InReportView() ) { @@ -2075,10 +2075,6 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) visibleEnd = visibleTo; } - wxRect rectLine; - int xOrig = dc.LogicalToDeviceX( 0 ); - int yOrig = dc.LogicalToDeviceY( 0 ); - // tell the caller cache to cache the data if ( IsVirtual() ) { @@ -2091,13 +2087,14 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetParent()->GetEventHandler()->ProcessEvent( evCache ); } - for ( size_t line = visibleFrom; line <= visibleEnd; line++ ) + wxRect rectLine(GetLineRect(visibleFrom)); + rectLine.Offset(origin); + + for (size_t line = visibleFrom; + line <= visibleEnd; + line++, rectLine.y += rectLine.height) { - rectLine = GetLineRect(line); - - - if ( !IsExposed(rectLine.x + xOrig, rectLine.y + yOrig, - rectLine.width, rectLine.height) ) + if ( !IsExposed(rectLine) ) { // don't redraw unaffected lines to avoid flicker continue; @@ -2120,7 +2117,6 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetLine(line)->DrawInReportMode( &dc, rectLine, - GetLineHighlightRect(line), IsHighlighted(line), line == m_current, IsItemChecked(line) ); @@ -2133,12 +2129,13 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) size_t i = visibleFrom; if (i == 0) i = 1; // Don't draw the first one - for ( ; i <= visibleEnd; i++ ) + + int y = (i - visibleFrom) * lineHeight; + for ( ; i <= visibleEnd; i++, y += lineHeight ) { dc.SetPen(pen); dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawLine(0 - dev_x, i * lineHeight, - clientSize.x - dev_x, i * lineHeight); + dc.DrawLine(0, y, clientSize.x, y); } // Draw last horizontal rule @@ -2146,8 +2143,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { dc.SetPen( pen ); dc.SetBrush( *wxTRANSPARENT_BRUSH ); - dc.DrawLine(0 - dev_x, (m_lineTo + 1) * lineHeight, - clientSize.x - dev_x , (m_lineTo + 1) * lineHeight ); + dc.DrawLine(0, y, clientSize.x, y); } } @@ -2160,7 +2156,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetItemRect(visibleFrom, firstItemRect); GetItemRect(visibleTo, lastItemRect); - int x = firstItemRect.GetX(); + int x = rectLine.x; dc.SetPen(pen); dc.SetBrush(* wxTRANSPARENT_BRUSH); @@ -2171,15 +2167,14 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { int colWidth = GetColumnWidth(col); x += colWidth; - int x_pos = x - dev_x; + int x_pos = x; if (col < GetColumnCount()-1) x_pos -= 2; int ruleHeight = m_extendRulesAndAlternateColour && visibleEnd > visibleTo ? clientHeight - : lastItemRect.GetBottom() + 1 - dev_y; + : lastItemRect.GetBottom() + 1; - dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y, - x_pos, ruleHeight); + dc.DrawLine(x_pos, firstItemRect.GetY() - 1, x_pos, ruleHeight); } } } @@ -2188,7 +2183,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) size_t count = GetItemCount(); for ( size_t i = 0; i < count; i++ ) { - GetLine(i)->Draw( &dc, i == m_current ); + GetLine(i)->Draw( &dc, origin, i == m_current ); } } @@ -2202,8 +2197,10 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) if ( IsHighlighted(m_current) ) flags |= wxCONTROL_SELECTED; - wxRendererNative::Get(). - DrawFocusRect(this, dc, GetLineHighlightRect(m_current), flags); + wxRect rect(GetLineHighlightRect(m_current)); + rect.Offset(origin); + + wxRendererNative::Get().DrawFocusRect(this, dc, rect, flags); } #endif // !__WXMAC__ }