Both Alvaro Quintana and Carlos Vargas have done research about DPI support on FWH.
# Recommended Approaches for Global UI Scaling in FiveWin
Based on the FiveWin codebase, here are the cleanest and most production-ready approaches to implement global 125% UI scaling without modifying individual dialogs:
1. Foundation: Enable DPI Awareness (Required First Step)
Add a manifest file to your application to declare DPI awareness. This is essential for Windows 10/11 to respect your application-level scaling: 0-cite-0
This tells Windows your application will handle DPI scaling itself, preventing Windows from applying bitmap scaling to your UI.
2. Recommended Approach: TLayoutManager Class (Newest & Cleanest)
FiveWin recently added the TLayoutManager class specifically for this purpose. It provides automatic scaling of sizes, positions, and fonts based on screen resolution: 0-cite-1
Key features:
- CalcSize() - Scales control sizes proportionally
- CalcPos() - Scales positions
- CalcFontSize() - Scales font sizes automatically
- Uses minimum factor to maintain aspect ratio 0-cite-2
This class was added in 2025 as a modern solution for high-resolution displays.
3. Global Font Scaling Approach (Production Pattern)
For a 125% scale factor, use the DPI detection function and apply scaled fonts globally:
Step A: Detect Current DPI 0-cite-3
This function returns the scaling factor (e.g., 1.25 for 125%, 1.5 for 150%).
Step B: Create Scaled Fonts 0-cite-4
Step C: Apply Font Globally Using TWindow Inheritance
The TWindow:GetFont() method implements recursive parent font inheritance. When you set a font on a parent window, child controls automatically inherit it: 0-cite-5
Production pattern (as shown in testfon3.prg): 0-cite-6
This pattern sets the font on the main window, then iterates through all controls to apply it globally.
4. System Default Font Override
You can override the system default font that FiveWin uses. When no font is specified, FiveWin creates one using: 0-cite-7
You can define a global scaled font at application startup and assign it to all windows/dialogs using the inheritance pattern above.
5. Alternative to MSGINFO() with Scaling Support
For message boxes, use the Alert() function instead of MSGINFO(). It creates a custom TDialog-based dialog that respects your application's font settings: 0-cite-8
Notice that Alert() uses GetSysFont() and creates a TDialog, which will inherit your global font settings, unlike the Windows MessageBox API used by MSGINFO().
6. Complete Working Example (DPI-Aware Dialog)
The scrolldlg.prg sample demonstrates a production-ready DPI-aware implementation: 0-cite-9
This shows how to:
- Get current DPI using GetDeviceCaps(hDC, LOGPIXELSX)
- Calculate scaling factor: nDpi * baseSize / 96
- Apply dynamically at runtime
7. Modern UI Components with Built-in DPI Scaling
The TMyTitle class (added October 2025) includes automatic DPI awareness: 0-cite-10
This demonstrates the framework's direction toward built-in DPI support in modern controls.
---
Recommended Production Strategy
For a clean 125% global scaling without modifying individual dialogs:
Add the DPI-aware manifest to your executable
At application startup, detect DPI and create scaled fonts:
nDpi := GetDpiForSystem() // or use DispFontPerSize() * 96
nScaleFactor := 1.25 // Your desired 125%
DEFINE FONT oAppFont NAME GetSysFont() SIZE 0, ScaleFontSize(-12, nDpi * nScaleFactor)
Apply font to main window (which propagates to all child controls via inheritance)
Use Alert() instead of MSGINFO() for scalable message boxes
For new development, consider using TLayoutManager for automatic scaling
For graphics, the GDI+ layer already supports DPI scaling through the dx variable
---
Notes
MSGINFO() limitation: It uses the Windows MessageBox API directly, which doesn't respect application fonts - only system DPI settings. This is why Alert() is recommended as an alternative.
Font inheritance: FiveWin's architecture automatically propagates fonts from parent windows to child controls, making global font scaling very effective.
RDP sessions: The manifest-based approach works well with RDP, as the DPI awareness is declared at the application level.
TLayoutManager is the most modern approach but requires refactoring to use its methods. The font scaling approach is simpler and works with existing code.
For truly comprehensive scaling (including control sizes, positions, spacing), you'll need to either use TLayoutManager or implement your own scaling calculations similar to the scrolldlg.prg example.
Citations
File: samples/ui/box/manifest.xml (L6-7)
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
File: source/classes/Tlayman.prg (L4-18)
CLASS TLayoutManager
DATA nScreenWidth, nScreenHeight // Current screen resolution
DATA nBaseWidth, nBaseHeight // Reference resolution (es. 1280x800)
DATA nSpacing // Spacing between controls
DATA nMarginTop, nMarginLeft // Upper and lower margins
DATA nMarginRight, nMarginBottom // Right and lower margins
METHOD New(nScreenWidth, nScreenHeight, nBaseWidth, nBaseHeight, nSpacing, nMarginTop, nMarginLeft, nMarginRight, nMarginBottom) CONSTRUCTOR
METHOD CalcSize(nBaseSize) // Calculate scaled size
METHOD CalcPos(nBasePos) // Calculate climbed position
METHOD CalcGridPos(nIndex, nItemsPerRow, nBaseWidth, nBaseHeight, nBaseTop, nBaseLeft) // Grid position
METHOD CalcFontSize(nBaseFontSize) // Calculate scaled font size
METHOD GetUsableWidth() //Usable width (excluding margins)
METHOD GetUsableHeight() // Usable height (excluding margins)
ENDCLASS
File: source/classes/Tlayman.prg (L49-51)
METHOD CalcFontSize(nBaseFontSize) CLASS TLayoutManager
// Calculate scaled font size
RETURN Int(nBaseFontSize * Min(::nScreenWidth / ::nBaseWidth, ::nScreenHeight / ::nBaseHeight))
File: source/function/getsysin.prg (L103-112)
function DispFontPerSize()
local hDC, nPixelX
hDC = CreateDC( "DISPLAY", "", "" )
nPixelX = GetDeviceCaps( hDC, LOGPIXELSX )
DeleteDC( hDC )
return ( nPixelX / 96 )
File: samples/ui/title/mytitle.prg (L91-92)
FUNCTION ScaleFontSize( nBaseSize, nDpi )
RETURN Int( nBaseSize * nDpi / 96 )
File: source/classes/window.prg (L3182-3204)
METHOD GetFont() CLASS TWindow
local hFont, aInfo, oFont
/*
if ::oFont == nil .and. ::oWnd != nil .and. ::oWnd:oFont != nil
::oFont = ::oWnd:oFont
::SendMsg( WM_SETFONT, ::oFont:hFont )
DEFAULT ::oFont:nCount := 0
::oFont:nCount++
return ::oFont
endif
*/
if ::oFont == nil
if ::oWnd != nil
::oFont = ::oWnd:GetFont()
if ::oFont != nil
::oFont:nCount++
::SendMsg( WM_SETFONT, ::oFont:hFont )
endif
endif
endif
File: source/classes/window.prg (L3226-3226)
DEFINE FONT ::oFont NAME GetSysFont() SIZE 0, -12 // BOLD
File: samples/test/testfon3.prg (L95-106)
STATIC FUNCTION REFRESHWND( oWnd, oFont )
LOCAL i
oWnd:SetFont( oFont )
FOR i = 1 TO LEN( oWnd:aControls )
oWnd:aControls[ i ]:SetFont( oFont )
oWnd:aControls[ i ]:Refresh()
NEXT
RETURN NIL
File: source/function/alert.prg (L34-60)
function Alert( cMsg, aOptions, cTitle, nDefault, xIcon )
#endif
Local oDlg, oFont
DEFAULT cMsg := "Alert dialog box" ,;
aOptions := {"&OK"} ,;
cTitle := "Attention" ,;
nDefault := 1
if CenterMsgs( "?" )
SetAsMsgBox()
endif
DEFINE FONT oFont NAME GetSysFont() SIZE NIL, -14
DEFINE DIALOG oDlg TITLE cTitle FONT oFont
oDlg:Cargo := 0
oDlg:lHelpIcon := .f.
ACTIVATE DIALOG oDlg ;
ON INIT ( Self, DlgInit(oDlg, oFont, cMsg, aOptions, cTitle, nDefault, xIcon) )
oFont:End()
RETURN oDlg:Cargo
File: samples/ui/dialogs/scrolldlg.prg (L51-74)
PROCEDURE Set_D_Height()
LOCAL nDpi := GetCurrentDpi()
d_height := (nDpi * 13 / 96)
RETURN
//============================================================================
// FUNCTION : GetCurrentDpi()
// Purpose : To Get the Windows Current DPI Setting
//============================================================================
FUNCTION GetCurrentDpi()
local hDc := GetDc(0)
local nDpi := GetDeviceCaps( hDC, LOGPIXELSX )
nDpi := GetDeviceCaps( hDC, LOGPIXELSX )
MsgInfo( LTRIM(STR(nDpi))+" DPI" )
ReleaseDC( 0, hDC )
RETURN nDpi
File: whatsnew.txt (L128-141)
* New: Class TMyTitle developed by Carlos Vargas. Please review samples\ui\mytitle.prg
A very nice class to create modern title bars.
**TMyTitle Class Functionality Summary:**
- **Gradient Backgrounds**: Supports horizontal and vertical gradient fills with customizable begin/end colors
- **Glass Effect**: Optional glass-like visual effect for modern UI appearance
- **Bitmap Integration**: Displays bitmaps with alpha channel support (ABPaint) and automatic DPI scaling
- **Typography**: Custom font support with precise text positioning and centering
- **Borders**: Optional borders with customizable colors
- **DPI Awareness**: Automatic font and bitmap scaling for high-resolution displays
- **Flexible Positioning**: Configurable offsets for bitmap and text placement
- **Resource Support**: Can load bitmaps from resources or external files
- **Color Customization**: Full control over gradient colors, text color, and border color
- **Cross-Platform**: Works with both 32-bit and 64-bit compilation
Master Plan: Modern UI Scaling & DPI Awareness in FiveWin
This comprehensive strategy synthesizes the newest framework features (v2025), community-proven patterns, and modern Windows API requirements to provide a robust 125%+ scaling solution.
- Global Infrastructure (Setup)
Application Manifest [MANDATORY]
Without a proper manifest, Windows will bitmap-stretch your UI, causing blurriness.
Action: Ensure your .manifest file declares PerMonitorV2 awareness.
Effect: Enables crisp UI rendering and accurate DPI reporting via GetDpiForSystem().
DPI Context Initialization
Action: Call ActivatePerMonitorV2() at the very beginning of Main().
Effect: Sets the process-level awareness required for dynamic scaling.
- Tier 1: Quick Scaling (Legacy Compatibility)
Best for existing applications requiring global scaling with minimal code changes.
Scaled Font Inheritance
Leverage FiveWin's recursive font propagation. child controls automatically inherit the font of their parent.
Action: Define a global scaled font and assign it as the default.
harbour
nDpi := GetDpiForSystem()
nScale := 1.25 // Your desired 125% factor
DEFINE FONT oAppFont NAME GetSysFont() SIZE 0, ScaleFontSize(-12, nDpi * nScale)
TWindow():oFontDefault := oAppFont
Redefining Message Boxes [RECOMMENDED]
Standard MsgInfo() uses the Windows API, which does not respect application fonts. Use Alert() as a scalable replacement.
Action: Add these global redefinitions:
harbour
#xtranslate MsgInfo( <cMsg>, [<cTitle>] ) => Alert( <cMsg>, {"&OK"}, <cTitle>, 1, 64 )
#xtranslate MsgAlert( <cMsg>, [<cTitle>] ) => Alert( <cMsg>, {"&OK"}, <cTitle>, 1, 48 )
- Tier 2: Precision Scaling (Modern Modules)
Recommended for new development to ensure perfect layout at any resolution.
Automated Layout Manager
The TLayoutManager class (2025) provides proportional scaling of fonts, sizes, and positions.
Usage: Initialize with design-time coordinates and use CalcSize() / CalcPos() for dynamic control placement.
DPI-Aware Controls
Favor modern controls like TMyTitle, which include built-in automatic scaling for bitmaps and text.
- Tier 3: Full Automation (Community Solution)
For high-end applications that must adapt perfectly when moving between monitors with different scaling factors.
Dynamic Class Modification
Modify core classes (TFont, TWindow, TXBrowse) to store design-level values and respond to WM_DPICHANGED.
Logic: Store noDpiScale_nInpHeight in TFont.
Automation: Implement DpiUpdate() in TWindow to iterate through all controls and recalculate coordinates/fonts using the relative factor provided by WM_DPICHANGED.
Verification Plan
Manifest Validation: Verify that the application is NOT being bitmap-scaled by Windows (text remains crisp).
Global Inheritance: Open a legacy dialog and confirm all controls (labels, buttons, browses) are using the scaled font.
Message Box Test: Verify that MsgInfo triggers a custom FiveWin dialog with scaled text.
Dynamic Resizing: Move the app between screens with different scaling and verify the UI resizes automatically (requires Tier 3 logic).