[Git][wxwidgets/wxwidgets][master] Fix wxPaintDC invalidation in wxMSW wxNotebook in dark mode

0 views
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
Aug 17, 2025, 7:12:30 PMAug 17
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • 365b07b7
    by Vadim Zeitlin at 2025-08-18T00:45:32+02:00
    Fix wxPaintDC invalidation in wxMSW wxNotebook in dark mode
    
    Claling GetTabRect() while painting wxNotebook could result in another
    WM_PAINT sent by the native control when using multiple tab rows and
    after handling this nested WM_PAINT wxMSW code called EndPaint() on the
    DC used by wxPaintDC that we had created before calling GetTabRect().
    
    This is almost certainly wrong and we should use reference counting
    instead of assuming that nothing can use the HDC once we return from
    WM_PAINT handler as the code seems to be doing currently, but for now
    just avoid the problem by calling GetTabRect() before creating wxPaintDC
    instead to ensure that wxPaintDC remains valid while we draw on it.
    
    Closes #25700.
    

2 changed files:

Changes:

  • include/wx/msw/notebook.h
    ... ... @@ -183,8 +183,9 @@ protected:
    183 183
       void OnEraseBackground(wxEraseEvent& event);
    
    184 184
       void OnPaint(wxPaintEvent& event);
    
    185 185
     
    
    186
    -  // Paint the notebook ourselves on the provided DC.
    
    187
    -  void MSWNotebookPaint(wxDC& dc);
    
    186
    +  // Paint the notebook ourselves using wxPaintDC (so this can be only called
    
    187
    +  // from wxEVT_PAINT handler).
    
    188
    +  void MSWNotebookPaint();
    
    188 189
     
    
    189 190
     
    
    190 191
       // true if we have already subclassed our updown control
    

  • src/msw/notebook.cpp
    ... ... @@ -1255,8 +1255,17 @@ DrawNotebookTab(wxWindow* win,
    1255 1255
     
    
    1256 1256
     } // anonymous namespace
    
    1257 1257
     
    
    1258
    -void wxNotebook::MSWNotebookPaint(wxDC& dc)
    
    1258
    +void wxNotebook::MSWNotebookPaint()
    
    1259 1259
     {
    
    1260
    +    // This is tricky: GetTabRect() may result in a nested WM_PAINT when the
    
    1261
    +    // native control decides to generate it from its Tab_CalcPaintMetrics()
    
    1262
    +    // for some reason (this happens at least when using multiple tab rows), so
    
    1263
    +    // we need to call it before creating wxPaintDC as otherwise the current
    
    1264
    +    // paint DC would be invalidated by EndPaint() while we use it, see #25700.
    
    1265
    +    wxRect rectTabArea = GetTabRect(0);
    
    1266
    +
    
    1267
    +    // Now create and use the DC.
    
    1268
    +    wxPaintDC dc(this);
    
    1260 1269
         dc.Clear();
    
    1261 1270
     
    
    1262 1271
         const wxDirection tabOrient = GetTabOrientation();
    
    ... ... @@ -1282,7 +1291,6 @@ void wxNotebook::MSWNotebookPaint(wxDC& dc)
    1282 1291
             return;
    
    1283 1292
     
    
    1284 1293
         // Start by erasing the tabs area background.
    
    1285
    -    wxRect rectTabArea = GetTabRect(0);
    
    1286 1294
         rectTabArea = ExpandSelectedTab(rectTabArea, tabOrient);
    
    1287 1295
         if ( tabOrient == wxTOP || tabOrient == wxBOTTOM )
    
    1288 1296
             rectTabArea.SetRight(sizeWindow.x);
    
    ... ... @@ -1370,16 +1378,16 @@ void wxNotebook::OnPaint(wxPaintEvent& event)
    1370 1378
             return;
    
    1371 1379
         }
    
    1372 1380
     
    
    1373
    -    wxPaintDC dc(this);
    
    1374
    -
    
    1375 1381
         if ( wxMSWDarkMode::IsActive() )
    
    1376 1382
         {
    
    1377 1383
             // We can't use default painting in dark mode, it just doesn't work
    
    1378 1384
             // there, whichever theme we use, so draw everything ourselves.
    
    1379
    -        MSWNotebookPaint(dc);
    
    1385
    +        MSWNotebookPaint();
    
    1380 1386
             return;
    
    1381 1387
         }
    
    1382 1388
     
    
    1389
    +    wxPaintDC dc(this);
    
    1390
    +
    
    1383 1391
         RECT rc;
    
    1384 1392
         ::GetClientRect(GetHwnd(), &rc);
    
    1385 1393
         if ( !rc.right || !rc.bottom )
    


View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help Notification message regarding https://gitlab.com/wxwidgets/wxwidgets/-/commit/365b07b75fb0b3e58f31468eda26727a57409141 at 1755472347

Reply all
Reply to author
Forward
0 new messages