wxDataViewTreeCtrl mirrored in RTL mode on Windows (Issue #26266)

101 views
Skip to first unread message

Steve Cornett

unread,
Mar 5, 2026, 1:15:50 PM (9 days ago) Mar 5
to wx-...@googlegroups.com, Subscribed
stevecor created an issue (wxWidgets/wxWidgets#26266)

Bug description:

The wxDataViewTreeCtrl control is rendered backwards/mirrored when in right-to-left layout mode on Windows. The problem appeared in 3.2.9.

The incorrect appearance:
image.png (view on web)

Expected appearance using 3.2.8:
image.png (view on web)

To Reproduce:

  1. On Windows 11, unpack wxWidgets-3.2.10.tar.bz2
  2. Run Visual Studio 2026
  3. Open build/wx_vc18.slnx and build Debug x64
  4. Open samples/dataview/dataview_vc9.vcproj and build Debug x64
  5. Run the program
  6. Click on the tab labelled wxDataViewTreeCtrl
  7. Use the menu command File Toggle layout direction
  8. The control has the incorrect appearance as shown above in this bug report

Platform and version information

Windows 11 25H2 x64
wxWidgets 3.2.10 wxMSW


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266@github.com>

VZ

unread,
Mar 5, 2026, 2:21:16 PM (9 days ago) Mar 5
to wx-...@googlegroups.com, Subscribed
vadz left a comment (wxWidgets/wxWidgets#26266)

This is really strange, I don't see anything obviously responsible for this in the list of commits between 3.2.8 and 3.2.9. The only commits touching wxDVC are 9de810e (Improve padding when using HiDPI in generic wxDataViewCtrl, 2025-10-15), 4704189 (Avoid collapsing wxDVC node if already done by event handler, 2025-07-14) and eec195c (Implement GetMainWindowOfCompositeControl for wxDataViewCtrl, 2025-05-07) but they don't seem to have anything to do with this.

If you can run git-bisect to find the exact commit which broke this, it would be most helpful.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4007169884@github.com>

AliKet

unread,
Mar 5, 2026, 6:28:47 PM (9 days ago) Mar 5
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

I am curious to know which commit breaks RTL in wx 3.2.9; however, the following patch should fix this issue in 3.2.9 as well as in master:

diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 7ae8c2a21e..b24b5a3c2c 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -2380,6 +2380,10 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
                     ysrc = hDIB - (ysrc + srcHeight);
                 }
 
+                // Force LTR layout for correct rendering in RTL layout
+                const auto oldLayoutDir = GetLayoutDirection();
+                SetLayoutDirection(wxLayout_LeftToRight);
+
                 if ( ::StretchDIBits(GetHdc(),
                                      xdest, ydest,
                                      dstWidth, dstHeight,
@@ -2397,6 +2401,8 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
                 {
                     success = true;
                 }
+
+                SetLayoutDirection(oldLayoutDir);
             }
         }
 


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4008441352@github.com>

AliKet

unread,
Mar 6, 2026, 3:05:41 AM (9 days ago) Mar 6
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

Sorry for the bad news, but anything using wxAutoBufferedPaintDC (which is a wxBufferedPaintDC) is broken in RTL layout under wxMSW in master!!!

What needs to be fixed then is wxBufferedPaintDC because using native auto bufferring (WS_EX_COMPOSITED) makes RTL working correctly.

I'll invistigate...


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4010206298@github.com>

Václav Slavík

unread,
Mar 6, 2026, 1:01:45 PM (8 days ago) Mar 6
to wx-...@googlegroups.com, Subscribed
vslavik left a comment (wxWidgets/wxWidgets#26266)

The immediate culprit is 46d47d3

That’s not the whole story, though. wxDVC RTL rendering is broken at least all the way back to 3.2.2 (I didn’t test further); I suspect this commit just made it worse. The breakage manifests in weird, hard to reproduce ways. I was initially confused that I couldn’t reproduce a user report matching this issue exactly - mirrored content. Instead, I got black rectangle.

Reverting 46d47d3 helped - I could see the first shown wxDVC fine now. Until I opened another wxDVC, which showed as black, and then re-opening the window that initially worked also showed as black from then on — the “bad” wxDVC instance would corrupt everything until I restarted the app. For background, I run Windows at 200% scale, on a 5120x2880 display. I eventually realized that size matters: everything would work with smaller windows at 100%. So far I did see:

  • black wxDVC content if it is too large, or if a large wxDVC was rendered at least once
  • smaller wxDVC showing copies of (somewhat corrupted) content of another large wxDVC
  • resizing a black-content wxDVC showing correct content on the margins, for a few px, on the opposite side than where it should be

I realize this is all hand-wavy and vague, but I don’t have better understanding (yet, anyway).

tl;dr: I think @AliKet is right to suspect wxBufferedPaintDC but 3.2.8 → 3.2.9 is a red herring; the actual underlying bug is much older.

For completeness, that patch doesn’t seem to have any observable effect here.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4013181741@github.com>

AliKet

unread,
Mar 9, 2026, 12:02:11 AM (6 days ago) Mar 9
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

Surprisingly, the following patch fixes the issue for me (tested with master), though I still don't have a satisfactory explanation for it.

diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 7ae8c2a21e..8cb3ac8c71 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -2366,10 +2366,12 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
                 // automatically as it doesn't even work with the source HDC.
                 // So do this manually to ensure that the coordinates are
                 // interpreted in the same way here as in all the other cases.
-                xsrc = source->LogicalToDeviceX(xsrcOrig);
-                ysrc = source->LogicalToDeviceY(ysrcOrig);
-                srcWidth = source->LogicalToDeviceXRel(srcWidth);
-                srcHeight = source->LogicalToDeviceYRel(srcHeight);
+                const auto pt = source->LogicalToDevice(xsrcOrig, ysrcOrig);
+                const auto sz = source->LogicalToDeviceRel(srcWidth, srcHeight);
+                xsrc = pt.x;
+                ysrc = pt.y;
+                srcWidth = sz.x;
+                srcHeight = sz.y;
 
                 // Figure out what co-ordinate system we're supposed to specify
                 // ysrc in.

BTW, the auidemo is also affected.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4020948841@github.com>

Václav Slavík

unread,
Mar 9, 2026, 2:24:48 PM (5 days ago) Mar 9
to wx-...@googlegroups.com, Subscribed
vslavik left a comment (wxWidgets/wxWidgets#26266)

Confirmed on 3.2 too, can’t reproduce any of the things I described above anymore — with just the patch above, not reverting 46d47d3


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4025853600@github.com>

VZ

unread,
Mar 9, 2026, 5:15:34 PM (5 days ago) Mar 9
to wx-...@googlegroups.com, Subscribed
vadz left a comment (wxWidgets/wxWidgets#26266)

Thanks, so the problem is that wxDC::DeviceToLogical[XY]{,Rel}() are broken in wxMSW when using RTL, right? We can reimplement them in terms of the 2-component version implemented natively, of course, but I'm not sure what exactly is wrong: is it just the missing multiplication by the axis sign or something else?

Can you please look at the difference between the results of the 2 sets of functions under debugger or add a wxLogDebug() call showing them?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4026958670@github.com>

AliKet

unread,
Mar 9, 2026, 9:14:46 PM (5 days ago) Mar 9
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

Confirmed on 3.2 too, can’t reproduce any of the things I described above anymore — with just the patch above, not reverting 46d47d3

Thank you for testing and confirming that the last patch works. There is one small correction needed, however: the xsrc, ysrc, srcWidth, and srcHeight parameters passed to StretchDIBits() must be specified in logical units, not device units, i.e: we should use
DeviceToLogical() instead of LogicalToDevice() and
DeviceToLogicalRel() instead of LogicalToDeviceRel()

Because otherwise scrolling is totally broken as can be seen in the dataview sample. auidemo and grid samples are also affected.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4027943420@github.com>

Václav Slavík

unread,
Mar 10, 2026, 6:13:02 AM (5 days ago) Mar 10
to wx-...@googlegroups.com, Subscribed
vslavik left a comment (wxWidgets/wxWidgets#26266)

Because otherwise scrolling is totally broken as can be seen in the dataview sample

If you mean it like this

const auto pt = source->DeviceToLogical(xsrcOrig, ysrcOrig);
const auto sz = source->DeviceToLogicalRel(srcWidth, srcHeight);

then I see the opposite on 3.2: this breaks scrolling in wxDVC, but it worked with the original version.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4030220046@github.com>

AliKet

unread,
Mar 10, 2026, 7:13:37 PM (4 days ago) Mar 10
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

Because otherwise scrolling is totally broken as can be seen in the dataview sample

If you mean it like this

const auto pt = source->DeviceToLogical(xsrcOrig, ysrcOrig);
const auto sz = source->DeviceToLogicalRel(srcWidth, srcHeight);

Yes

then I see the opposite on 3.2: this breaks scrolling in wxDVC, but it worked with the original version.

I switched to v3.2.10 and none of the patches fix the scrolling issue. But with the last patch everything works correctly for me after reverting this commit 288b208 as is done in master in this commit 0387253 and also this one f5d326f


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4035053888@github.com>

AliKet

unread,
Mar 10, 2026, 7:44:33 PM (4 days ago) Mar 10
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

This is how it works (scrolling dataview sample) under my system:

[Bas] :

https://github.com/user-attachments/assets/48e9d078-3e9e-4b37-829a-b6d5d5ead836

[Good] :

https://github.com/user-attachments/assets/e86e7e95-ea05-43e5-ad3d-54084b8524eb

The last video is the result of applying the fixes I mentioned in the comment above.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4035176462@github.com>

AliKet

unread,
Mar 12, 2026, 2:32:37 AM (3 days ago) Mar 12
to wx-...@googlegroups.com, Subscribed
AliKet left a comment (wxWidgets/wxWidgets#26266)

Sorry for making some noise here, but I think I finally managed to fix this issue (in master at least) with this patch, which works for me in both layouts: LTR as well as RTL:

diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 7ae8c2a21e..756fc44ee5 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -2145,7 +2145,9 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
     xdest += XLOG2DEV(0);
     ydest += YLOG2DEV(0);
 
-    const int xsrcOrig = xsrc;
+    // As m_signX is always positive regardless of the layout, the value returned by
+    // XLOG2DEV must be negated if the layout direction is RTL.
+    const int xsrcOrig = GetLayoutDirection() == wxLayout_LeftToRight ? xsrc : -xsrc;
     const int ysrcOrig = ysrc;
 
     // This does the same thing as XLOG2DEV() but for the source DC.
@@ -2366,10 +2368,13 @@ bool wxMSWDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest,
                 
// automatically as it doesn't even work with the source HDC.
                 // So do this manually to ensure that the coordinates are
                 // interpreted in the same way here as in all the other cases.
-                xsrc = source->LogicalToDeviceX(xsrcOrig);
-                ysrc = source->LogicalToDeviceY(ysrcOrig);
-                srcWidth = source->LogicalToDeviceXRel(srcWidth);
-                srcHeight = source->LogicalToDeviceYRel
(srcHeight);
+                const auto pt = source->LogicalToDevice(xsrcOrig, ysrcOrig);
+                const auto sz = source->LogicalToDeviceRel(srcWidth, srcHeight);
+
+                xsrc = pt.x;
+                ysrc = pt.y;
+                srcWidth = sz.x;
+                srcHeight = sz.y;
 
                 
// Figure out what co-ordinate system we're supposed to specify
                 // ysrc in.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4044322562@github.com>

VZ

unread,
Mar 12, 2026, 11:12:20 AM (2 days ago) Mar 12
to wx-...@googlegroups.com, Subscribed
vadz left a comment (wxWidgets/wxWidgets#26266)

There have been no replies to me previous comment but I still think we need to fix LogicalToDevice[XY]{Rel,}() instead of replacing them.

I realize now that m_signX should indeed be +1 even in RTL. But this just means that we should add an extra factor of -1 to these functions when RTL layout is used, shouldn't we?

Or, alternatively, just reimplement them in terms of natively implemented functions without X and Y in their name.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/26266/4047544631@github.com>

Reply all
Reply to author
Forward
0 new messages