Integrate the DPIAware.h changes from TortoiseSVN
[TortoiseGit.git] / src / Utils / DPIAware.h
blobd0cdfc5d7cf4b989daea1ced963802e03f92bb8a
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2018 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #pragma once
21 class CDPIAware
23 private:
24 CDPIAware()
25 : m_fInitialized(false)
26 , m_dpi(96)
27 , pfnGetDpiForWindow(nullptr)
28 , pfnGetDpiForSystem(nullptr)
29 , pfnGetSystemMetricsForDpi(nullptr)
30 , pfnSystemParametersInfoForDpi(nullptr)
32 ~CDPIAware() {}
34 public:
35 static CDPIAware& Instance()
37 static CDPIAware instance;
38 return instance;
41 private:
42 // Get screen DPI.
43 int GetDPI() { _Init(); return m_dpi; }
45 // Convert between raw pixels and relative pixels.
46 int Scale(int x) { _Init(); return MulDiv(x, m_dpi, 96); }
47 float ScaleFactor() { _Init(); return m_dpi / 96.0f; }
48 int Unscale(int x) { _Init(); return MulDiv(x, 96, m_dpi); }
49 public:
50 inline int GetDPIX() { return GetDPI(); }
51 inline int GetDPIY() { return GetDPI(); }
52 inline int ScaleX(int x) { return Scale(x); }
53 inline int ScaleY(int y) { return Scale(y); }
54 inline float ScaleFactorX() { return ScaleFactor(); }
55 inline float ScaleFactorY() { return ScaleFactor(); }
56 inline int UnscaleX(int x) { return Unscale(x); }
57 inline int UnscaleY(int y) { return Unscale(y); }
58 inline int PointsToPixelsX(int pt) { return PointsToPixels(pt); }
59 inline int PointsToPixelsY(int pt) { return PointsToPixels(pt); }
61 // Determine the screen dimensions in relative pixels.
62 int ScaledScreenWidth() { return _ScaledSystemMetric(SM_CXSCREEN); }
63 int ScaledScreenHeight() { return _ScaledSystemMetric(SM_CYSCREEN); }
65 // Scale rectangle from raw pixels to relative pixels.
66 void ScaleRect(__inout RECT *pRect)
68 pRect->left = Scale(pRect->left);
69 pRect->right = Scale(pRect->right);
70 pRect->top = Scale(pRect->top);
71 pRect->bottom = Scale(pRect->bottom);
74 // Scale Point from raw pixels to relative pixels.
75 void ScalePoint(__inout POINT *pPoint)
77 pPoint->x = Scale(pPoint->x);
78 pPoint->y = Scale(pPoint->y);
81 // Scale Size from raw pixels to relative pixels.
82 void ScaleSize(__inout SIZE *pSize)
84 pSize->cx = Scale(pSize->cx);
85 pSize->cy = Scale(pSize->cy);
88 // Determine if screen resolution meets minimum requirements in relative pixels.
89 bool IsResolutionAtLeast(int cxMin, int cyMin)
91 return (ScaledScreenWidth() >= cxMin) && (ScaledScreenHeight() >= cyMin);
94 private:
95 // Convert a point size (1/72 of an inch) to raw pixels.
96 int PointsToPixels(int pt) { _Init(); return MulDiv(pt, m_dpi, 72); }
98 public:
99 // returns the system metrics. For Windows 10, it returns the metrics dpi scaled.
100 UINT GetSystemMetrics(int nIndex)
102 return _ScaledSystemMetric(nIndex);
105 // returns the system parameters info. If possible adjusted for dpi.
106 UINT SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
108 _Init();
109 UINT ret = 0;
110 if (pfnSystemParametersInfoForDpi)
111 ret = pfnSystemParametersInfoForDpi(uiAction, uiParam, pvParam, fWinIni, m_dpi);
112 if (ret == 0)
113 ret = ::SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni);
114 return ret;
117 // Invalidate any cached metrics.
118 void Invalidate() { m_fInitialized = false; }
120 private:
122 // This function initializes the CDPIAware Class
123 void _Init()
125 if (!m_fInitialized)
127 auto hUser = ::GetModuleHandle(L"user32.dll");
128 if (hUser)
130 pfnGetDpiForWindow = (GetDpiForWindowFN*)GetProcAddress(hUser, "GetDpiForWindow");
131 pfnGetDpiForSystem = (GetDpiForSystemFN*)GetProcAddress(hUser, "GetDpiForSystem");
132 pfnGetSystemMetricsForDpi = (GetSystemMetricsForDpiFN*)GetProcAddress(hUser, "GetSystemMetricsForDpi");
133 pfnSystemParametersInfoForDpi = (SystemParametersInfoForDpiFN*)GetProcAddress(hUser, "SystemParametersInfoForDpi");
136 if (pfnGetDpiForSystem)
138 m_dpi = pfnGetDpiForSystem();
140 else
142 HDC hdc = GetDC(nullptr);
143 if (hdc)
145 // Initialize the DPI member variable
146 // This will correspond to the DPI setting
147 // With all Windows OS's to date the X and Y DPI will be identical
148 m_dpi = GetDeviceCaps(hdc, LOGPIXELSX);
149 ReleaseDC(nullptr, hdc);
152 m_fInitialized = true;
156 // This returns a 96-DPI scaled-down equivalent value for nIndex
157 // For example, the value 120 at 120 DPI setting gets scaled down to 96
158 // X and Y versions are provided, though to date all Windows OS releases
159 // have equal X and Y scale values
160 int _ScaledSystemMetric(int nIndex)
162 _Init();
163 if (pfnGetSystemMetricsForDpi)
164 return pfnGetSystemMetricsForDpi(nIndex, m_dpi);
165 return MulDiv(::GetSystemMetrics(nIndex), 96, m_dpi);
168 private:
169 typedef UINT STDAPICALLTYPE GetDpiForWindowFN(HWND hWnd);
170 typedef UINT STDAPICALLTYPE GetDpiForSystemFN();
171 typedef UINT STDAPICALLTYPE GetSystemMetricsForDpiFN(int nIndex, UINT dpi);
172 typedef UINT STDAPICALLTYPE SystemParametersInfoForDpiFN(UINT uiAction,UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi);
174 GetDpiForWindowFN* pfnGetDpiForWindow;
175 GetDpiForSystemFN* pfnGetDpiForSystem;
176 GetSystemMetricsForDpiFN* pfnGetSystemMetricsForDpi;
177 SystemParametersInfoForDpiFN* pfnSystemParametersInfoForDpi;
179 // Member variable indicating whether the class has been initialized
180 bool m_fInitialized;
182 int m_dpi;