diff --git a/src/widgets/OverlayPanel.cpp b/src/widgets/OverlayPanel.cpp index 1e6e8f9c8..bbd5e2d30 100644 --- a/src/widgets/OverlayPanel.cpp +++ b/src/widgets/OverlayPanel.cpp @@ -37,11 +37,11 @@ void OverlayPanel::ClearOverlays() mOverlays.clear(); } -void OverlayPanel::DrawOverlays(bool repaint, wxDC *pDC) +void OverlayPanel::DrawOverlays(bool repaint_all, wxDC *pDC) { size_t n_pairs = mOverlays.size(); - std::vector< std::pair > pairs; + std::vector< std::pair > pairs; pairs.reserve(n_pairs); // Find out the rectangles and outdatedness for each overlay @@ -53,12 +53,15 @@ void OverlayPanel::DrawOverlays(bool repaint, wxDC *pDC) // If not, then whatever is outdated, and whatever will be damaged by // undrawing. // By redrawing only what needs it, we avoid flashing things like - // the cursor that are drawn with invert. - if (!repaint) { + // the cursor that are drawn with invert, and also avoid + // unnecessary work. + bool some_overlays_need_repainting = repaint_all; + if (!repaint_all) { bool done; do { done = true; for (size_t ii = 0; ii < n_pairs; ++ii) { + some_overlays_need_repainting |= pairs[ii].second; for (size_t jj = ii + 1; jj < n_pairs; ++jj) { if (pairs[ii].second != pairs[jj].second && pairs[ii].first.Intersects(pairs[jj].first)) { @@ -70,6 +73,14 @@ void OverlayPanel::DrawOverlays(bool repaint, wxDC *pDC) } while (!done); } + if (!some_overlays_need_repainting) { + // This function (OverlayPanel::DrawOverlays()) is called at + // fairly high frequency through a timer in TrackPanel. In case + // there is nothing to do, we exit early because creating the + // wxClientDC below is expensive, at least on Linux. + return; + } + Maybe myDC; auto &dc = pDC ? *pDC : (myDC.create(this), *myDC); @@ -77,7 +88,7 @@ void OverlayPanel::DrawOverlays(bool repaint, wxDC *pDC) bool done = true; auto it2 = pairs.begin(); for (auto pOverlay : mOverlays) { - if (repaint || it2->second) { + if (repaint_all || it2->second) { done = false; pOverlay->Erase(dc, GetBackingDC()); } @@ -88,7 +99,7 @@ void OverlayPanel::DrawOverlays(bool repaint, wxDC *pDC) if (!done) { it2 = pairs.begin(); for (auto pOverlay : mOverlays) { - if (repaint || it2->second) { + if (repaint_all || it2->second) { // Guarantee a clean state of the dc each pass: ADCChanger changer{ &dc }; diff --git a/src/widgets/OverlayPanel.h b/src/widgets/OverlayPanel.h index b5b3fa8d9..208786544 100644 --- a/src/widgets/OverlayPanel.h +++ b/src/widgets/OverlayPanel.h @@ -22,7 +22,7 @@ public: // default as for wxPanel: long style = wxTAB_TRAVERSAL | wxNO_BORDER); - // Register and unregister overlay objects. + // Registers and unregisters overlay objects. // The sequence in which they were registered is the sequence in // which they are painted. // OverlayPanel is not responsible for their memory management. @@ -31,9 +31,14 @@ public: bool RemoveOverlay(Overlay *pOverlay); void ClearOverlays(); - // Erase and redraw things like the cursor, cheaply and directly to the - // client area, without full refresh. - void DrawOverlays(bool repaint, wxDC *pDC = nullptr); + // Erases and redraws to the client area the overlays that have + // been previously added with AddOverlay(). If "repaint_all" is + // true, all overlays will be erased and re-drawn. Otherwise, only + // the ones that are out-of-date, as well as the intersecting ones, + // will be erased and re-drawn. + // pDC can be null, in which case, DrawOverlays() will create a + // wxClientDC internally when necessary. + void DrawOverlays(bool repaint_all, wxDC *pDC = nullptr); private: std::vector mOverlays;