Jump to content
A.M. Hoornweg

DPI Awareness, tForm.CurrentPPI and PixelsPerInch not always identical !!???

Recommended Posts

Hello World,

 

I'm trying to debug some dpi-awareness problems in an application of mine (using Delphi 11 on a Windows 10 X64 VM).  I have a 3-screen setup with different scaling factors for testing (from left to right: 300%, 100% and 175%). I test dpi awareness by dragging my main form between these screens

 

Most of the time the re-scaling kinda works (albeit slow), but sometimes things get wonky and I wanted to know why. This main form of mine is a rather complex one and it needs some time to redraw when the screen DPI changes. I'm trying to reduce that amount of time but in this case the VCL components themselves are kinda sluggish.

 

For diagnostic purposes I have overridden the method tForm.DoAfterMonitorDpiChanged() to output some debugging information and the outcome puzzles me.

 

procedure tMyForm.DoAfterMonitorDpiChanged(OldDPI, NewDPI: Integer);
begin
  inherited;
  OutputDebugString(Pchar(Format('Currentppi / Pixelsperinch  %d / %d',[currentppi, pixelsperinch])));
end;

Most of the time the values of CurrentPPI and PixelsPerInch are identical and reflect the value of the screen where the form was dragged to, but occasionally they go out of sync

 

When that happens, one of the two contains the DPI of the new screen where I moved the form, whilst the other one reflects the dpi of the screen where the form used to be. This happens especially if the dragging was "fast".

When I look into the source code of unit vcl.forms, I see that the developer usually sets both properties to the same value. So I assume this behaviour to be a bug. Also, I fail to understand why tForm needs both these properties if they are intended to always be the same value. Unfortunately I can't consult the on-line help because https://docwiki.embarcadero.com has been down since yesterday.  Can anyone shed some light to this, and maybe try to reproduce the behavior?

 

 

 

 

dpi out of sync.png

Share this post


Link to post
59 minutes ago, A.M. Hoornweg said:

When I look into the source code of unit vcl.forms, I see that the developer usually sets both properties to the same value.

That is not quite right. It is FCurrentPPI that copied to FPixelsPerInch, but you are showing CurrentPPI and PixelsPerInch instead. While the latter retrieves FPixelsPerInch inside TWinControl.GetPixelsPerInch, the former not always does that for FCurrentPPI in TControl.GetCurrentPPI. There is a chance that GetDPIForWinow retrieves another value as is stored in FCurrentPPI. Of course that can still be some error - and it probably is.

Share this post


Link to post

One observation: 

 

in unit Vcl.Forms there's an optimization in tCustomForm.WMDPICHanged which ensures that a form is only re-scaled when Message.YDPI is unequal to fCurrentPPI.

 

Assuming that fCurrentPPI may not be perfectly reliable, I have removed that optimization just for testing.  And bingo, my form now appears to re-scale properly every time.

 

    //unit vcl.forms.pas method tCustomForm.WMDPICHANGED
    
    if (* (Message.YDpi <> fCurrentppi) *) and Scaled then
    begin
      DoBeforeMonitorDpiChanged(fCurrentppi, Message.YDpi);
      OldPPI := fCurrentppi;
      ScaleForPPIRect(Message.YDpi, Message.ScaledRect);
      FCurrentPPI := Message.YDpi;
      fPixelsPerInch := FCurrentPPI;
      DoAfterMonitorDpiChanged(OldPPI, FCurrentPPI);
    end;

 

 

 

Also I've found out that constraints may be problematic in Delphi.

 

Normally, when a form is dragged to a new monitor having a different scaling factor and its center reaches the new monitor, Windows sends a wm_dpichanged message to the window's wndproc to inform it of the new resolution and also gives it a pointer to a rectangle containing a proposed new position and size. The form must then redraw itself using the proposed position and size to ensure that  the scaled window is definitely on that new monitor.

 

However, constraints in VCL components can enforce size limits to components and to the form itself.  So it may very well be that after the positioning and resizing, the center of the form is suddenly back on the previous monitor ...

 

 

  • Like 1

Share this post


Link to post
5 minutes ago, A.M. Hoornweg said:

However, constraints in VCL components can enforce size limits to components and to the form itself.  So it may very well be that after the positioning and resizing, the center of the form is suddenly back on the previous monitor ...

 

Can you provide a concrete example? The people responsible for that are way more open for discussion when they have a actual code that fails.

Share this post


Link to post
47 minutes ago, A.M. Hoornweg said:

However, constraints in VCL components can enforce size limits to components and to the form itself.  So it may very well be that after the positioning and resizing, the center of the form is suddenly back on the previous monitor ...

Nice catch! 👌

Share this post


Link to post

I'll see if I can concoct an example next week. It's hard to extract from my current program. I can tell you that it definitely happens in some forms of mine that have some panels with constraints and other panels with align=alClient, it causes these forms to "explode" when they are dragged between monitors. 

 

By trial and error I could stop it from happening by protecting WMDPICHANGED against recursions. 

 

procedure tMyForm.WMDPIChanged(var Msg: TWMDpi);
begin
  inc(fChangingDPI);
  try
    if fChangingDPI = 1
    then
      inherited    
    else
      Msg.Result := 0;
  finally
    dec(fChangingDPI);
  end;  
end;

 

Share this post


Link to post
6 minutes ago, A.M. Hoornweg said:

By trial and error I could stop it from happening by protecting WMDPICHANGED against recursions. 

 

That is quite some valuable information. 👍

Share this post


Link to post
26 minutes ago, Uwe Raabe said:

That is quite some valuable information. 👍

Thanks.  I have stumbled upon a ton of bugs in dpi-awareness so far but I haven't had the time yet to report them to QC because that usually requires test cases.   

 

Another subtle one: If you use tScrollbox, you need to set tScrollbox.Vertscrollbar.Position to zero before a DPI change, otherwise some components on the tScrollbox may become unreachable after the scaling (the ones near the top). 

Share this post


Link to post
36 minutes ago, A.M. Hoornweg said:

I have stumbled upon a ton of bugs in dpi-awareness so far but I haven't had the time yet to report them to QC because that usually requires test cases.

Indeed! I have been struggling with this myself several times. Often providing a fix is simpler than constructing a decent test case.

Share this post


Link to post
7 minutes ago, Anders Melander said:

By the way, am I the only one that has problems with the CAPTCHA at quality.embarcadero.com ? I always have to answer the challenge 3 times before it accepts my answer.

Welcome to the club! For me it often helps to refresh the captcha a few times before answering it.

Share this post


Link to post
8 hours ago, Anders Melander said:

And there's even an easy fix.

The easy fix did not work for me. 

8 hours ago, Anders Melander said:

By the way, am I the only one that has problems with the CAPTCHA at quality.embarcadero.com ? I always have to answer the challenge 3 times before it accepts my answer.

I've had this issue for years - but I will say that I have not had it for the last week or so - no idea why. Hoping it doesn't return. 

Share this post


Link to post
11 hours ago, Anders Melander said:

I always have to answer the challenge 3 times

I just type garbage for the first two now, then try and read that idiotic picture on the third one..

Share this post


Link to post

I only started getting CAPTCHAs last month. Before that nothing. Maybe they only have a limited number of them so there's not enough for everyone to get them?... 🤔

  • Haha 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×