Funny that people in Berlin and Montreal should have the same doubts and discussions about the nature of the current season.
This planet is, indeed, a small one.
So, DPI wisdom from our resident PHC* is that we should stick to the prudent, but labour-intensive, approach. Sounds like good advice, but lots of work.
And here I am, still mourning for those glorious days when PB was completely WYSIWYG, when we didn't have to wring our brains so much just to make sure that windows and gadgets ended up looking as we dreamed them to be. Ah, the good old days of last year (or so)...
Thanks for taking the time to pass on the wisdom.
* Pointy Hat Coders
Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware progs
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
"That's not a bug..." said the programmer. "it's a feature! "
"Oh! I see..." replied the blind man.
"Oh! I see..." replied the blind man.
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
PB 5.60 (x64) running under Windows 10 1703 on a Dell portable with a High DPI screen.
I've used Little John's code (read his post here) as an include file and tested it mercilessly. I've found it to work perfectly every single time when I compile my program. However, I kept coming across a font problem when running my code from within the IDE : often (not every time, which, in itself, is baffling... ) the font would be too large, even though it turned out to be OK in the compiled output.
Using lots of Debug statements everywhere, I finally spotted the problem: when DPI awareness is inherited from the parent, the font size gets scaled accordingly, which works fine for the compiled result, but displays wrongly when running the code from within the IDE.
So I added a test for inheritance (that's what I called it; you may disagree ), allowing the font size to be scaled or not, depending on whether the code is compiled or run from the IDE.
Rather than posting a heavily modified file or pointing out every single line where I've made changes, I simply reproduce below Little John's entire code, carefully marking 10 lines as either "Added" or "Modified":
On my system, I've reworded the code to my liking, and made it into an include file, which has worked for me without fail ever since I started using it. I've tested th solution on a different machine with a regular 96.0 DPI screen and it also works well there. I've not been able, however, to test it for all the combinations that Little John looked into.
This is only a slight enhancement/correction to Little John's code.
I'm very grateful to him for a smart, simple and effective solution to the DPI problem.
I've used Little John's code (read his post here) as an include file and tested it mercilessly. I've found it to work perfectly every single time when I compile my program. However, I kept coming across a font problem when running my code from within the IDE : often (not every time, which, in itself, is baffling... ) the font would be too large, even though it turned out to be OK in the compiled output.
Using lots of Debug statements everywhere, I finally spotted the problem: when DPI awareness is inherited from the parent, the font size gets scaled accordingly, which works fine for the compiled result, but displays wrongly when running the code from within the IDE.
So I added a test for inheritance (that's what I called it; you may disagree ), allowing the font size to be scaled or not, depending on whether the code is compiled or run from the IDE.
Rather than posting a heavily modified file or pointing out every single line where I've made changes, I simply reproduce below Little John's entire code, carefully marking 10 lines as either "Added" or "Modified":
Code: Select all
; successfully tested with all combinations of
; - Windows XP, 7, 10 Creators update
; - DPI 125%, 150%
; - PB 5.31, 5.44 LTS, 5.60
; modified by Blue (10 lines are marked 'added' or 'modified')
; so that running from inside the IDE displays the same as the compiled output
DeclareModule Std
; [...]
Declare.f FactorDPIx()
Declare.f FactorDPIy()
EndDeclareModule
Module Std
EnableExplicit
; [...]
CompilerIf #PB_Compiler_Version < 540
Structure RTL_OSVERSIONINFOEXW
dwOSVersionInfoSize.l
dwMajorVersion.l
dwMinorVersion.l
dwBuildNumber.l
dwPlatformId.l
szCSDVersion.u[128]
wServicePackMajor.w
wServicePackMinor.w
wSuiteMask.w
wProductType.b
wReserved.b
EndStructure
Prototype.i pRtlGetVersion (*ver.RTL_OSVERSIONINFOEXW)
#STATUS_SUCCESS = 0
Procedure.i _IsWindows81OrNewer()
; In PB 5.31, OSVersion() returns e.g. 90 on Windows 8 and also
; on Windows 10. So with older PB versions that function can't
; be used to check the current Windows version reliably.
; Therefore in order to check whether the current OS is Windows
; 8.1 or newer, this self-written procedure is used here.
;
; out: #True if the currently running OS is Windows 8.1 or newer,
; #False otherwise
Protected ver.RTL_OSVERSIONINFOEXW
Protected RtlGetVersion.pRtlGetVersion
Protected hDLL.i
ver\dwOSVersionInfoSize = SizeOf(ver)
hDLL = OpenLibrary(#PB_Any, "ntdll.dll")
If hDLL
RtlGetVersion = GetFunction(hDLL, "RtlGetVersion")
CloseLibrary(hDLL)
EndIf
If RtlGetVersion = 0 Or RtlGetVersion(@ ver) <> #STATUS_SUCCESS
ProcedureReturn #False
EndIf
If ver\dwPlatformId <> #VER_PLATFORM_WIN32_NT
ProcedureReturn #False
EndIf
If (ver\dwMajorVersion = 6 And ver\dwMinorVersion = 3) Or
ver\dwMajorVersion > 6
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
CompilerEndIf
Prototype.i pIsProcessDPIAware()
Prototype.i pSetProcessDPIAware()
Define s_InitDPI.i=#False, s_ScaleDPIx.f=1.0, s_ScaleDPIy.f=1.0
;-
Procedure _InitScaleDPI()
; Windows 5.0 or higher needed for minimum functionality of this procedure
; [modified after <http://www.purebasic.fr/english/viewtopic.php?f=12&t=40507>, 2010-01-02
; see also <http://msdn.microsoft.com/en-us/library/windows/desktop/dd464660%28v=vs.85%29.aspx>
; <http://blogs.msdn.com/b/oldnewthing/archive/2004/07/14/182971.aspx>
; <http://www.purebasic.fr/english/viewtopic.php?p=462177#p462177>
; <http://www.purebasic.fr/english/viewtopic.php?f=13&t=62043>]
Shared s_InitDPI, s_ScaleDPIx, s_ScaleDPIy
Protected IsProcessDPIAware.pIsProcessDPIAware
Protected SetProcessDPIAware.pSetProcessDPIAware
Protected.i user32, hdc, dlgFont, dpiaware=#False
Protected inherited=#False, dlgFontsize.f = 9.0 ;- . <<< Added
CompilerIf #PB_Compiler_ExecutableFormat = #PB_Compiler_Executable
; Only use this in EXEs, as DLLs inherit DPI from the calling process.
; This part is Windows 6.x+ only (Vista and newer) and must be done before using
; GetDeviceCaps().
user32 = OpenLibrary(#PB_Any, "user32.dll")
If user32
IsProcessDPIAware = GetFunction(user32, "IsProcessDPIAware")
If IsProcessDPIAware
dpiaware = IsProcessDPIAware()
EndIf
CompilerIf #PB_Compiler_IsMainFile
Debug "DPI-aware: " + dpiaware
CompilerEndIf
; If the exe is allready DPI aware (like through a manifest), then we skip using
; the set DPI aware function.
If dpiaware = #False
SetProcessDPIAware = GetFunction(user32, "SetProcessDPIAware")
If SetProcessDPIAware
If SetProcessDPIAware()
CompilerIf #PB_Compiler_IsMainFile
Debug "Set DPI: OK"
CompilerEndIf
EndIf
EndIf
Else ; <<< Added
inherited= #True ;- . <<< Added
EndIf ; <<< Added
CloseLibrary(user32)
EndIf
CompilerEndIf
hdc = GetDC_(#Null) ; get handle to the device context for the entire screen
If hdc
s_ScaleDPIx = GetDeviceCaps_(hdc, #LOGPIXELSX) / 96.0 ; 96 is the default DPI value on Windows.
s_ScaleDPIy = GetDeviceCaps_(hdc, #LOGPIXELSY) / 96.0
ReleaseDC_(#Null, hdc)
EndIf
CompilerIf #PB_Compiler_Version < 540
If _IsWindows81OrNewer()
CompilerIf #PB_Compiler_IsMainFile
Debug "Windows 8.1 or newer"
CompilerEndIf
; Here the font sizes are adjusted automatically.
dlgFont = LoadFont(#PB_Any, "Segoe UI", dlgFontsize, #PB_Font_HighQuality) ;- . <<< Modified
If dlgFont
SetGadgetFont(#PB_Default, FontID(dlgFont))
EndIf
EndIf
CompilerElse
If OSVersion() >= #PB_OS_Windows_8_1
CompilerIf #PB_Compiler_IsMainFile
Debug "Windows 8.1 or newer"
CompilerEndIf
; Here the font sizes are not adjusted automatically.
If Not inherited ; <<< Added
dlgFontsize = 9.0*s_ScaleDPIy ;- . <<< Added
EndIf ; <<< Added
dlgFont = LoadFont(#PB_Any, "Segoe UI", dlgFontsize, #PB_Font_HighQuality) ;- . <<< Modified
If dlgFont
SetGadgetFont(#PB_Default, FontID(dlgFont))
Debug "; " + #PB_Compiler_Line +": font size set to " + dlgFontsize ;- . <<< Added
EndIf
EndIf
CompilerEndIf
s_InitDPI = #True
EndProcedure
;-
Procedure.f FactorDPIx()
Shared s_InitDPI, s_ScaleDPIx
If s_InitDPI = #False
_InitScaleDPI()
EndIf
ProcedureReturn s_ScaleDPIx
EndProcedure
Procedure.f FactorDPIy()
Shared s_InitDPI, s_ScaleDPIy
If s_InitDPI = #False
_InitScaleDPI()
EndIf
ProcedureReturn s_ScaleDPIy
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
; -- Demo
EnableExplicit
Global g_ScaleDPIx.f, g_ScaleDPIy.f
g_ScaleDPIx = Std::FactorDPIx()
g_ScaleDPIy = Std::FactorDPIy()
Macro DPIx (_x_)
(_x_) * g_ScaleDPIx
EndMacro
Macro DPIy (_y_)
(_y_) * g_ScaleDPIy
EndMacro
If OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore, DPIx(120), DPIy(70), "" ) = 0
MessageRequester("Fatal error", "Can't open main window.")
End
EndIf
TextGadget(#PB_Any, DPIx(30), DPIy(20), DPIx(60), DPIy(20), "DPI: " + StrF(100*g_ScaleDPIy,0) + " %", #PB_Text_Border)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
CompilerEndIf
This is only a slight enhancement/correction to Little John's code.
I'm very grateful to him for a smart, simple and effective solution to the DPI problem.
"That's not a bug..." said the programmer. "it's a feature! "
"Oh! I see..." replied the blind man.
"Oh! I see..." replied the blind man.
-
- Enthusiast
- Posts: 118
- Joined: Thu May 17, 2007 8:35 pm
- Location: USA
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
Had you guys read this yet?
https://blogs.windows.com/buildingapps/ ... 3vTV9Yh.97
Also looked at the api here?
https://msdn.microsoft.com/en-us/librar ... 2147217396
https://blogs.windows.com/buildingapps/ ... 3vTV9Yh.97
Also looked at the api here?
https://msdn.microsoft.com/en-us/librar ... 2147217396
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
Hi Blue,
I remember well that I was rather happy when I was able to come up with this code, because I desperately needed something like that. Now I am glad to read that the code is useful for you, too. And thanks for your very kind words, you are most welcome! Many thanks also for testing the code so thoroughly, and for fixing that bug. It is so good to know that someone else has tested the code rigorously! And documenting your changes so carefully is very kind.
In my message which you have referenced in your previous post, there is now a link to your improved code -- and also in the first post of this thread.
Maybe I've got a suggestion for a tiny simplification of your improvement:
If I'm not mistaken, then your new variable inherited is #True if and only if the variable dpiaware is #True. So couldn't we just do without the variable inherited, and then instead of writing we could write
Best regards!
I remember well that I was rather happy when I was able to come up with this code, because I desperately needed something like that. Now I am glad to read that the code is useful for you, too. And thanks for your very kind words, you are most welcome! Many thanks also for testing the code so thoroughly, and for fixing that bug. It is so good to know that someone else has tested the code rigorously! And documenting your changes so carefully is very kind.
In my message which you have referenced in your previous post, there is now a link to your improved code -- and also in the first post of this thread.
Maybe I've got a suggestion for a tiny simplification of your improvement:
If I'm not mistaken, then your new variable inherited is #True if and only if the variable dpiaware is #True. So couldn't we just do without the variable inherited, and then instead of writing
Code: Select all
If Not inherited
Code: Select all
If Not dpiaware
Best regards!
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
Thanks for the feedback, Little John.Little John wrote: [...]
Maybe I've got a suggestion for a tiny simplification of your improvement:
If I'm not mistaken, then your new variable inherited is #True if and only if the variable dpiaware is #True. So couldn't we just do without the variable inherited, and then instead of writingwe could writeCode: Select all
If Not inherited
Code: Select all
If Not dpiaware
Best regards!
Firstly, let me address your suggestion of doing away with the "inherited" Boolean.
At the risk of sounding reactionary, I would say no, it won't work. In my experience anyway. At first, I was doing exactly as you suggest; but I kept getting uneven results : sometimes the result looked fine, sometimes it didn't. That's the very "gotcha" that had me pulling my hair and going around in circles for hours. And when I write hours, it's not a figure of speech. I really spent hours figuring this out.
A piece of code flagged as dpiaware sometimes looks wrong when run from within the IDE, then looks fine, while consistently looking fine, of course, when compiled to an exe. (That part of the mystery, the inconsistency from within the IDE, I haven't figured out yet) When I finally spotted the problem line and introduced the "inherited" Boolean in all the right places, I started getting consistent results, no matter whatever the IDE is doing.
But, in the end, alas! you may be correct after all: as you know, the more you work on a bug, the less you see it. Nothing will ever beat a fresh pair of eyes coupled to a sharp brain.
Secondly, when I point out the importance of your code to users who, like me, enjoy a high DPI system, I'm not being polite or friendly. I truly mean that it has been a life saver. Your code, with its masterful little macros, has made PB enjoyable again. And I suspect that, as high DPI displays/systems become more common, more and more PB users will come to discover and appreciate it... until it gets built into PB (version 12.1 or 12.2, maybe ?)
"That's not a bug..." said the programmer. "it's a feature! "
"Oh! I see..." replied the blind man.
"Oh! I see..." replied the blind man.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
Hello Blue,
thank you for your detailed explanation. I see now that we better should leave your code exactly as it is. And many thanks again for all your work involved in isolating and fixing the issue!
thank you for your detailed explanation. I see now that we better should leave your code exactly as it is. And many thanks again for all your work involved in isolating and fixing the issue!
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: Win 8.1+ AND PB 5.40+: Fonts too small in DPI-aware prog
I have read it. However, I don't know how to transform that information into working and helpful PureBasic code. If you can do so, please share your knowledge with us.Mike Yurgalavage wrote:Had you guys read this yet?
https://blogs.windows.com/buildingapps/ ... 3vTV9Yh.97
Also looked at the api here?
https://msdn.microsoft.com/en-us/librar ... 2147217396