Opened 2 years ago

Last modified 9 months ago

#18090 confirmed defect

wrong xor line is drawn when I drag the wxSplitterWindow' sash bar with wxSP_LIVE_UPDATE disabled

Reported by: ollydbg Owned by:
Priority: normal Milestone:
Component: wxMSW Version: 3.1.3
Keywords: splitter HiDPI Cc: ericj
Blocked By: Blocking: #18474
Patch: no

Description

Build the samples\splitter\splitter.cpp under Windows by MinGW GCC compiler with wxWidgtes 3.1.0 or 3.1.1-rc

In my Windows 7 64bit system, I see an issue that when I drag the sash bar, the xor line does not drawn under the cursor, but has an offset to the mouse cursor.

This bug only happens when the Windows performance setting "Enable Desktop composition" is checked on.

I originally post the issue to wxWidgets's forum: When drag the sash line of wxSplitterWindow, the target line has offset, and some screen shot was post as attachment there, and an user "doublemax" has discovered that "Enable Desktop composition" option is the reason, he does not have the same issue as mine, but "whole redraw becomes slow and flickery".

I also post and discuss with VZ under wx's maillist: wrong xor line is drawn when I drag the wxSplitterWindow' sash bar with wxSP_LIVE_UPDATE disabled - Google Groups, here also some screen shots showns that the sub-window divided by the sash bar is not correct.

In the wxWidgets' forum post, I also debugged this issue under GDB(in Windows), and found that the function "void wxSplitterWindow::OnSize(wxSizeEvent& event)" is called several times, but the last time, a wrong size value is passed in.

Change History (9)

comment:1 Changed 2 years ago by vadz

  • Component changed from GUI-generic to wxMSW
  • Keywords HiDPI added

As mentioned in this post, this could be due to a mismatch between scaling/not scaling coordinates in high DPI.

comment:2 Changed 2 years ago by ollydbg

  • Cc asmwarrior@… added

OK, I can confirm it is the HiDPI related issue.

Running the executable from the batch file like below don't have such issue.

@set "__COMPAT_LAYER=~ HIGHDPIAWARE" & start "" /max "mysplittertest.exe"

comment:3 Changed 2 years ago by ericj

  • Cc ericj added

I did a little more testing (under Windows 7/64):

As probably known, Windows will run a non dpi-aware application in an emulation mode on HiDPI displays. The application will only "see" a smaller display.

E.g. i tested on a physical screen with 1680x1050 and set the scaling to 150%. The application only sees a display of 1120x700 which will also be reflected when calling ClientToScreen().

wxScreenDC however always expects "real" coordinates, this explains the offset of the lines being drawn.

This affects all code that uses wxScreenDC to write onto the screen, e.g. the "dragimag" sample.

However, i also found out that the application will *not* run in an emulation mode if "Enable Desktop composition" is switched off. This was new to me.

In order to solve this, we'd need a way to find out if an application runs in an emulation mode, but i can't think of any way to do that. And even if it was possible, i'm not sure if would be worth the effort.

comment:4 follow-up: Changed 2 years ago by vadz

  • Status changed from new to confirmed

We probably need to stop using wxScreenDC for drawing, it's not implemented under non-MSW platforms and doesn't seem to be necessary here.

comment:5 follow-up: Changed 2 years ago by ollydbg

  • Cc asmwarrior@… removed

I agree with VZ's idea, I think when drag the sash bar, the line should always be drawn inside the client window.

comment:6 in reply to: ↑ 5 Changed 2 years ago by rozmansi

  • Cc simon@… added

Replying to ollydbg:

I agree with VZ's idea, I think when drag the sash bar, the line should always be drawn inside the client window.

I've changed the code to paint on client DC (instead of screen DC). But the wxSplitterWindow's Z-order is behind its children. Therefore, if you paint the sash bar on wxSplitterWindow's client DC it will occur behind its children.

Unfortunately, all mouse-dragging visual feedback should be painted on wxScreenDC to ensure it is not overlapped by some control.

comment:7 in reply to: ↑ 4 Changed 2 years ago by rozmansi

  • Cc simon@… removed

Replying to vadz:

We probably need to stop using wxScreenDC for drawing, it's not implemented under non-MSW platforms and doesn't seem to be necessary here.

Yes, all wxScreenDC painting is affected: wxSplitterWindow, wxAuiManager, wxSashWindow...

There are a few solutions to this issue:

  1. Microsoft fixes the screen DC, so it fully operates in virtualized coordinates for the non-DPI–aware applications that are being virtualized. The core of this problem is that only client painting is virtualized. Screen painting is not - while screen DC reports all metrics virtualized. This inconsistency is giving us headaches.
  1. wxWidgets detects it is being virtualized (See https://stackoverflow.com/a/36864741/2071884) and re-implements all GDI painting in wxScreenDCImpl to convert virtualized coordinates to real coordinates. This is quite some work and I already might have oversimplified things.

Or fix screen DC to return real metrics - not virtualized. Client painting should use client DC to get metrics - IMO the wxWindowBase::GetContentScaleFactor(), wxWindowBase::FromDIP() and wxWindowBase::ToDIP() are wrong to use screen DC.

  1. Use wxSP_LIVE_UPDATE with wxSplitterWindow. This will avoid the sash bar.
  1. Port your application to DPI-aware: where client and screen DPI meet again.

Pick your poison!

(I am taking the option no. 4: It fixes things in the long-term and apps look awesome on 192dpi.)

Last edited 2 years ago by rozmansi (previous) (diff)

comment:8 Changed 12 months ago by vadz

  • Blocking 18474 added

comment:9 Changed 9 months ago by vadz

  • Version changed from 3.1.0 to 3.1.3

FWIW I can confirm that this works correctly for DPI-aware applications (e.g. if you use per-monitor v2 DPI awareness in the manifest) with 3.1.3.

Bad news is that it still doesn't work without it.

Note: See TracTickets for help on using tickets.