-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathDPIAware.h
177 lines (154 loc) · 6.5 KB
/
DPIAware.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// sktoolslib - common files for SK tools
// Copyright (C) 2018, 2020-2021 - Stefan Kueng
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#pragma once
class CDPIAware
{
private:
CDPIAware()
: pfnGetDpiForWindow(nullptr)
, pfnGetDpiForSystem(nullptr)
, pfnGetSystemMetricsForDpi(nullptr)
, pfnSystemParametersInfoForDpi(nullptr)
, m_fInitialized(false)
, m_dpi(96)
{
}
~CDPIAware() {}
public:
static CDPIAware &Instance()
{
static CDPIAware instance;
return instance;
}
// Get screen DPI.
int GetDPI(HWND hWnd)
{
_Init();
if (pfnGetDpiForWindow && hWnd)
{
return pfnGetDpiForWindow(hWnd);
}
return m_dpi;
}
// Convert between raw pixels and relative pixels.
int Scale(HWND hWnd, int x) { return MulDiv(x, GetDPI(hWnd), 96); }
float ScaleFactor(HWND hWnd) { return GetDPI(hWnd) / 96.0f; }
float ScaleFactorSystemToWindow(HWND hWnd) { return static_cast<float>(GetDPI(hWnd)) / static_cast<float>(m_dpi); }
int Unscale(HWND hWnd, int x) { return MulDiv(x, 96, GetDPI(hWnd)); }
// Determine the screen dimensions in relative pixels.
int ScaledScreenWidth() { return _ScaledSystemMetric(SM_CXSCREEN); }
int ScaledScreenHeight() { return _ScaledSystemMetric(SM_CYSCREEN); }
// Scale rectangle from raw pixels to relative pixels.
void ScaleRect(HWND hWnd, __inout RECT *pRect)
{
pRect->left = Scale(hWnd, pRect->left);
pRect->right = Scale(hWnd, pRect->right);
pRect->top = Scale(hWnd, pRect->top);
pRect->bottom = Scale(hWnd, pRect->bottom);
}
// Scale Point from raw pixels to relative pixels.
void ScalePoint(HWND hWnd, __inout POINT *pPoint)
{
pPoint->x = Scale(hWnd, pPoint->x);
pPoint->y = Scale(hWnd, pPoint->y);
}
// Scale Size from raw pixels to relative pixels.
void ScaleSize(HWND hWnd, __inout SIZE *pSize)
{
pSize->cx = Scale(hWnd, pSize->cx);
pSize->cy = Scale(hWnd, pSize->cy);
}
// Determine if screen resolution meets minimum requirements in relative pixels.
bool IsResolutionAtLeast(int cxMin, int cyMin)
{
return (ScaledScreenWidth() >= cxMin) && (ScaledScreenHeight() >= cyMin);
}
// Convert a point size (1/72 of an inch) to raw pixels.
int PointsToPixels(HWND hWnd, int pt) { return MulDiv(pt, GetDPI(hWnd), 72); }
// returns the system metrics. For Windows 10, it returns the metrics dpi scaled.
UINT GetSystemMetrics(int nIndex)
{
return _ScaledSystemMetric(nIndex);
}
// returns the system parameters info. If possible adjusted for dpi.
UINT SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
{
_Init();
UINT ret = 0;
if (pfnSystemParametersInfoForDpi)
ret = pfnSystemParametersInfoForDpi(uiAction, uiParam, pvParam, fWinIni, m_dpi);
if (ret == 0)
ret = ::SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
return ret;
}
// Invalidate any cached metrics.
void Invalidate() { m_fInitialized = false; }
private:
// This function initializes the CDPIAware Class
void _Init()
{
if (!m_fInitialized)
{
auto hUser = ::GetModuleHandle(L"user32.dll");
if (hUser)
{
pfnGetDpiForWindow = reinterpret_cast<GetDpiForWindowFn *>(GetProcAddress(hUser, "GetDpiForWindow"));
pfnGetDpiForSystem = reinterpret_cast<GetDpiForSystemFn *>(GetProcAddress(hUser, "GetDpiForSystem"));
pfnGetSystemMetricsForDpi = reinterpret_cast<GetSystemMetricsForDpiFn *>(GetProcAddress(hUser, "GetSystemMetricsForDpi"));
pfnSystemParametersInfoForDpi = reinterpret_cast<SystemParametersInfoForDpiFn *>(GetProcAddress(hUser, "SystemParametersInfoForDpi"));
}
if (pfnGetDpiForSystem)
{
m_dpi = pfnGetDpiForSystem();
}
else
{
HDC hdc = GetDC(nullptr);
if (hdc)
{
// Initialize the DPI member variable
// This will correspond to the DPI setting
// With all Windows OS's to date the X and Y DPI will be identical
m_dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(nullptr, hdc);
}
}
m_fInitialized = true;
}
}
// This returns a 96-DPI scaled-down equivalent value for nIndex
// For example, the value 120 at 120 DPI setting gets scaled down to 96
// X and Y versions are provided, though to date all Windows OS releases
// have equal X and Y scale values
int _ScaledSystemMetric(int nIndex)
{
_Init();
if (pfnGetSystemMetricsForDpi)
return pfnGetSystemMetricsForDpi(nIndex, m_dpi);
return MulDiv(::GetSystemMetrics(nIndex), 96, m_dpi);
}
private:
using GetDpiForWindowFn = UINT STDAPICALLTYPE(HWND hWnd);
using GetDpiForSystemFn = UINT STDAPICALLTYPE();
using GetSystemMetricsForDpiFn = UINT STDAPICALLTYPE(int nIndex, UINT dpi);
using SystemParametersInfoForDpiFn = UINT STDAPICALLTYPE(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi);
GetDpiForWindowFn * pfnGetDpiForWindow;
GetDpiForSystemFn * pfnGetDpiForSystem;
GetSystemMetricsForDpiFn * pfnGetSystemMetricsForDpi;
SystemParametersInfoForDpiFn *pfnSystemParametersInfoForDpi;
// Member variable indicating whether the class has been initialized
bool m_fInitialized;
int m_dpi;
};