Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
WINDOWS Set DPI Awareness
#1
Code: (Select All)
Declare Dynamic Library "user32"
    Function DPI& Alias SetProcessDpiAwarenessContext (ByVal dpiContext As _Offset)
End Declare
Const UNAWARE = -1, AWARE = -2, PER_MONITOR_AWARE = -3
Const PER_MONITOR_AWARE_V2 = -4, UNAWARE_GDISCALED = -5

_FullScreen

Dim result As Integer
Print _DesktopWidth, _DesktopHeight
Sleep
Print "Setting DPI Awareness Context..."

_FullScreen _Off 'Note if you use _FULLSCREEN, you should turn it OFF before making any change
_Delay .2 'And give it a delay to make certain that it can make that change

result = DPI(AWARE) 'change to setting you like
Print _DesktopWidth, _DesktopHeight
_FullScreen _Stretch
Sleep
System

With the above, a windows user can set DPI Awareness as they wish for their programs.  Note that once Awareness is turned off, the system ignores all other calls so you can't just turn it off and on all willy-nilly.

And what *IS* DPI Awareness?  It's the automatic scaling of a program according to the settings you have in your window display settings.
For example, if you have your system set to 200% scaling, it's going to automatically scale all your programs 200% in size.

For a 3840 x 2160 display, this means that the biggest program screen you can make and view would be 1920 x 1080 as it'd scale 200% to fill the 3840 x 2160 display completely.

So with this, you can set your program to decide if it wants to do that scaling or not.  

If your program is DPI(Aware), it means you're going to do any necessary scaling yourself.
If it's DPI(UnAware), it means you're going to let the system do that automatic scaling.
By monitor is going to depend on your scaling settings on each monitor and where the program is located on the desktop.



Chances are, if you don't know what DPI Awareness is or that Windows automagically resizes and scales things for you, then you won't need to worry about this.  This is mainly something that affects people with scale factors built into their system (like many laptops -- mine defaults to 200% scaling) and if you've never noticed it in the past, then it's probably not something you need to concern yourself about anytime soon.  Wink
Reply
#2
Thank you. I was just messing about with DPI-aware controls in a another programming package. 

This is more impressive in windowed mode. Now I can actually create a program that's the real screen width of my system (or closer to it), without having to mess with settings. Thanks again.
Reply
#3
thank you Steve Smile 
how about a cross-platform solution  Big Grin
Reply
#4
(Yesterday, 08:32 PM)James D Jarvis Wrote: Thank you. I was just messing about with DPI-aware controls in a another programming package. 

This is more impressive in windowed mode. Now I can actually create a program that's the real screen width of my system (or closer to it), without having to mess with settings. Thanks again.

One thing to note -- you may want to set $SCREENHIDE at the start of your program, before you set the DPI Awareness.  The Windows documentation reads:

Quote:You must call this API before you call any APIs that depend on the DPI awareness (including before creating any UI in your process).

So technically you're supposed to call this before making any graphical windows and such, to prevent problems.  I'd suggest something like:
Code: (Select All)

$SCREENHIDE

Declare Dynamic Library "user32"
    Function DPI& Alias SetProcessDpiAwarenessContext (ByVal dpiContext As _Offset)
End Declare
Const UNAWARE = -1, AWARE = -2, PER_MONITOR_AWARE = -3
Const PER_MONITOR_AWARE_V2 = -4, UNAWARE_GDISCALED = -5

result = DPI(Aware)
_DELAY 0.2 'always nice for a slight delay in this type of thing to make certain windows has time to register changes.
_SCREENSHOW

SCREEN _NEWIMAGE(Wide, Tall, Mode)  <-- set as desired here

(OR similar.  I haven't actually tested the above, so just use it as an illustration of the program flow you'd want to set up.  If that doesn't work on the first try, look up the SCREENHIDE and SCREENSHOW examples on the wiki and sort out whatever quirk I may have missed in the proper syntax/usage.)

(Yesterday, 08:39 PM)Jack Wrote: thank you Steve Smile 
how about a cross-platform solution  Big Grin

Wish I could, but I'm a windows user.  I know about squat about linux/mac, but I imagine they'd be quite a bit more difficult to sort out.  

Linux is definitely gonna be a cluster since there's both X and Wayland and they handle it differently.

I'll leave it to the other devs to sort those OSes out. Best I can do is offer this little tidbit for our windows' users. Wink
Reply
#5
A tested and running version, which I commented fairly extensively for everyone.  If someone has troubles with this after this... It's probably an OS issue.  This won't work on any version of Windows prior to Windows 10.  It won't work on Linux or Mac.  DPI Awareness is a relatively new thing and older versions of windows didn't have it.  (At least not this many options of it, it dates back to Win 8, IIRC.)

The basic concept is:
Hide the screen.
Set the DPI Awareness.
Set the Desired Screen.
Unhide the screen.
Then move/tweak the screen with other commands as desired.

Working demo is below.  (Resolutions may need changing as this is what my laptop has for max settings and what I tested it on.  Your own laptop/monitor/system may very well be configured differently.)

Code: (Select All)
'First, hide the screen before making any DPI Awareness changes
$ScreenHide

Declare Dynamic Library "user32"
    Function DPI& Alias SetProcessDpiAwarenessContext (ByVal dpiContext As _Offset)
End Declare
Const UNAWARE = -1, AWARE = -2, PER_MONITOR_AWARE = -3
Const PER_MONITOR_AWARE_V2 = -4, UNAWARE_GDISCALED = -5

result = DPI(AWARE) 'Change the DPI Awareness to the mode you want your program to run under.
'Note that this is a one time ONLY change. Once set, it can't be altered by any other process or
'future call to the routine.  This is an OS feature and not something which can be changed by the
'programmer, or any QB64PE dev.
_Delay .2 'always nice for a slight delay in this type of thing to make certain windows has time to register changes.

Screen _NewImage(3840, 2160, 32) ' <-- set as desired here
_ScreenShow 'Show the screen after the awareness is set and the mode is created as you desire
_ScreenMove _Middle 'note that you can't move a hidden screen so place this AFTER the _ScreenShow if applicable
'note also that _FullScreen or any other type commands should come AFTER that _ScreenShow as well
'if you try them earlier, you're just asking for trouble.  Just save yourself the headache and degugging
'and put any other graphic commands AFTER the _ScreenShow.

'Don't forget to load a font which is readable for the screen without automatic scaling in play
'on my laptop, it's 200% scaling so a 1920x1080 screen scales to fit my 3840x2160 screen resolution.
'so going by that logic, I'm just going to scale my normal 16 pixel font to be a 32 pixel font.
f = _LoadFont("courbd.ttf", 32, "monospace") '32 pixel (estimated) fontheight
_Font f
Print "Hello World"

'And after all this, my screen should look normal on my laptop, but have a 4k resolution.
'So I can display images to a much higher resolution without downscaling or losing any details.
Reply




Users browsing this thread: 1 Guest(s)