Jump to content
luebbe

Per monitor DPI awareness - how to prevent flickering?

Recommended Posts

Hi Folks,

 

I've got two 24" monitors with different resolutions:

  1. 2560x1440 -> 122ppi
  2. 1920x1080 -> 92ppi

 

Application is set to per-monitor-dpi-v2.

Window's scaling is set to 125% on the WQHD monitor. If it is at 100%, the application doesn't get any dpi-change notifications. They should be called "windows scaling change notifications". 😏

 

When I move the application window between the monitors, there is a lot of flickering going on until all controls are redrawn. Depending on the number of controls, this can take a "while".

Is there a way to avoid this visible flickering, in order to get a smoother transition between monitors?

 

Just for laughs: switch your monitor scaling between 100% and 125% with the IDE window open... 😈

Share this post


Link to post
procedure TForm1.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI,
  NewDPI: Integer);
begin
  LockWindowUpdate(0);
end;
 
procedure TForm1.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI,
  NewDPI: Integer);
begin
  LockWindowUpdate(Handle);
end;
  • Like 1
  • Thanks 2
  • Sad 1

Share this post


Link to post
1 hour ago, luebbe said:

1920x1080 -> 92ppi

!? Why not 96 to avoid scaling?

Edited by pyscripter

Share this post


Link to post

Lovely! Thanks a lot!

 

So I have to live with the delay, which is kind of ok, when there is no more flickering. Maybe I should show a popup "Rescaling form, please wait" 😉

Now I only have to cope with the numerous rounding errors, that make toolbar buttons and other controls shrink over time.

Share this post


Link to post
30 minutes ago, pyscripter said:
procedure TForm1.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI,
  NewDPI: Integer);
begin
  LockWindowUpdate(0);
end;
 
procedure TForm1.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI,
  NewDPI: Integer);
begin
  LockWindowUpdate(Handle);
end;

I do the same thing when switching themes, but haven't tried this. I wonder how it will go with moving the window from one monitor to the other with different dpi's. At the moment it's terrible, flickers and stops moving for a few seconds.
 

Share this post


Link to post
4 minutes ago, pyscripter said:

!? Why not 96 to avoid scaling?

That value was calculated from monitor size and resolution. The IDE is set to 96 and 96 is stored in the .dfm files.

The (Before|After)MonitorDpiChanged methods report changes from 96<->120 dpi (scaling by 1,25).

Share this post


Link to post
43 minutes ago, Vincent Parrett said:

I do the same thing when switching themes, but haven't tried this. I wonder how it will go with moving the window from one monitor to the other with different dpi's. At the moment it's terrible, flickers and stops moving for a few seconds.
 

Kiriakos' suggestion works fine. The window is still unresponsive for a few seconds, but at least the flicker is gone.

Edited by luebbe

Share this post


Link to post

There are a number of ways to reduce scaling time:

  • If you are using VirtualLists with many Icons try RtlVclFixes.pas
  • Use ParentFont := True in child controls to avoid scaling fonts
  • For custom components try to fine-tune/override DefaultScalingFlags  
  • Like 1
  • Thanks 2

Share this post


Link to post
Guest
49 minutes ago, pyscripter said:

Use ParentFont := True in child controls to avoid scaling fonts

Of course... had not crossed this feeble mind. Cool!

Share this post


Link to post
Guest
2 hours ago, luebbe said:

Just for laughs: switch your monitor scaling between 100% and 125% with the IDE window open... 😈

Perhaps add some EULA-like clauses to cover thine behind?

Share this post


Link to post
42 minutes ago, luebbe said:

I guess I don't need the other fixes with 10.4.1.

InputBox/Query are still broken.

Share this post


Link to post

A 'trick' we used to improve the behavior while moving windows between monitors was to create a bitmap when the user starts dragging and use this image while dragging. It works very good and only when the user releases the mouse you need to do rescaling.

  • Like 1

Share this post


Link to post
3 hours ago, Vincent Parrett said:

LockWindowUpdate

Hm, the use of LockWindowUpdate is strongly discouraged by Microsoft:

Quote

The purpose of the LockWindowUpdate function is to permit drag/drop feedback to be drawn over a window without interference from the window itself. The intent is that the window is locked when feedback is drawn and unlocked when feedback is complete. LockWindowUpdate is not intended for general-purpose suppression of window redraw. Use the WM_SETREDRAW message to disable redrawing of a particular window.

Some gotchas of LockWindowUpdate: What does LockWindowUpdate do?

And even worse, this describes exactly your use case: With what operations is LockWindowUpdate not meant to be used?

 

Some remarks on WM_SETREDRAW here: The Unfortunate Effect of WM_SETREDRAW

No idea whether these still apply, the blog post is from 2011.

Edited by dummzeuch
  • Like 1

Share this post


Link to post

@dummzeuchAll these limitations of LockWindowUpdate are well known and noted.   Yes you should avoid using LockWindowUpdate if you can and prefer WM_SETREDRAW.  Fully agree.  WM_SETREDRAW was the first thing I tried and did not work.

 

As Raymond Chen says in the above articles

Quote

By now, you’ve probably noticed a common thread to all of these LockWindowUpdate scenarios: They all involve dragging of some sort. Dragging a window caption to move it, dragging the edge of a window to resize it, dragging an item into a window, or dragging an item out of a window. This is not a coincidence. The LockWindowUpdate function was designed with these drag scenarios in mind. Since dragging an item uses the mouse button, and there’s only one mouse, you can’t have multiple drag operations in progress at once, and therefore, there’s no need to lock more than one window for update at a time. The function should perhaps more accurately have been named LockDragWindow.

One can well argue therefore, that dragging a Window from one monitor to another is a valid case for using LockWindowUpdate. If it is OK to lock the whole desktop when you do OLE drag&drop it should be OK to lock a single window while dragging it between monitors, just for the time it rescales.

 

Edited by pyscripter
  • Like 4

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

×