File: Win32Dpi.cpp

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (194 lines) | stat: -rw-r--r-- 5,727 bytes parent folder | download | duplicates (3)
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "stdafx.h"
#include "Win32Dpi.h"

namespace gui {
	// Default DPI (i.e. 100%, no scaling).
	const Nat defaultDpi = 96;
}

#ifdef GUI_WIN32

namespace gui {

	// From the MSDN documentation.
#ifndef DPI_AWARENESS_CONTEXT_UNAWARE
#define DPI_AWARENESS_CONTEXT_UNAWARE              ((DWORD)-1)
#endif
#ifndef DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE         ((DWORD)-2)
#endif
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE    ((DWORD)-3)
#endif
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DWORD)-4)
#endif
#ifndef DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED
#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED    ((DWORD)-5)
#endif

	enum PROCESS_DPI_AWARENESS {
		PROCESS_DPI_UNAWARE,
		PROCESS_SYSTEM_DPI_AWARE,
		PROCESS_PER_MONITOR_DPI_AWARE
	};

	// DPI awareness mode.
	enum DpiMode {
		// Not DPI aware.
		dpiNone,

		// System DPI aware (i.e., checks at startup, but not afterwards).
		dpiSystem,

		// Per-monitor DPI aware (i.e., dynamically responds to changes).
		dpiMonitor,
	};

	// Current DPI mode.
	static DpiMode dpiMode;

	// Do we want to call "EnableNonClientScaling" (using the non-v2 mode of per monitor in Windows 8.1)?
	static bool callNonClientScaling;

	// Misc. Win32 functions we load. These might be null.
	typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND);
	EnableNonClientDpiScaling enableNonClientDpiScaling;
	typedef UINT (WINAPI *GetDpiForSystem)();
	GetDpiForSystem getDpiForSystem;
	typedef UINT (WINAPI *GetDpiForWindow)(HWND);
	GetDpiForWindow getDpiForWindow;
	typedef int (WINAPI *GetSystemMetricsForDpi)(int, UINT);
	GetSystemMetricsForDpi getSystemMetricsForDpi;
	typedef BOOL (WINAPI *SystemParametersInfoDpi)(UINT, UINT, LPVOID, UINT, UINT);
	SystemParametersInfoDpi systemParametersInfoDpi;
	typedef BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT, DWORD, BOOL, DWORD, UINT);
	AdjustWindowRectExForDpi adjustWindowRectExForDpi;

	void setDpiAware() {
		HMODULE user32 = GetModuleHandle(L"user32.dll");
		dpiMode = dpiNone;
		callNonClientScaling = false;

		enableNonClientDpiScaling = (EnableNonClientDpiScaling)GetProcAddress(user32, "EnableNonClientDpiScaling");
		getDpiForSystem = (GetDpiForSystem)GetProcAddress(user32, "GetDpiForSystem");
		getDpiForWindow = (GetDpiForWindow)GetProcAddress(user32, "GetDpiForWindow");
		getSystemMetricsForDpi = (GetSystemMetricsForDpi)GetProcAddress(user32, "GetSystemMetricsForDpi");
		systemParametersInfoDpi = (SystemParametersInfoDpi)GetProcAddress(user32, "SystemParametersInfoForDpi");
		adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)GetProcAddress(user32, "AdjustWindowRectExForDpi");

		// Windows 10 and onwards (per monitor v2)
		typedef BOOL (WINAPI *SetDpiContext)(DWORD);
		SetDpiContext dpiContext = (SetDpiContext)GetProcAddress(user32, "SetProcessDpiAwarenessContext");
		if (dpiContext && dpiContext(DWORD(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))) {
			dpiMode = dpiMonitor;
			return;
		}

		// Windows 8.1 and onwards. If we're not on Windows 10 (1607), this will leave menus and
		// window border unscaled (which the Microsoft samples do not deal with, so we won't either).
		{
			// Note: This is a known DLL, so this does not pose any danger of loading the wrong DLL.
			HMODULE shcore = LoadLibrary(L"SHCORE.DLL");

			typedef HRESULT (WINAPI *SetDpiProcess)(PROCESS_DPI_AWARENESS);
			SetDpiProcess dpiProcess = (SetDpiProcess)GetProcAddress(shcore, "SetProcessDpiAwareness");
			if (dpiProcess && dpiProcess(PROCESS_PER_MONITOR_DPI_AWARE) == S_OK) {
				dpiMode = dpiMonitor;
				callNonClientScaling = true;
			}

			FreeLibrary(shcore);

			if (dpiMode != dpiNone)
				return;
		}

		typedef void (WINAPI *SetDpiAware)();
		SetDpiAware dpiAware = (SetDpiAware)GetProcAddress(user32, "SetProcessDPIAware");
		if (dpiAware) {
			dpiAware();
			dpiMode = dpiSystem;
		}
	}

	void enableNcScaling(HWND hWnd) {
		if (!callNonClientScaling)
			return;

		if (enableNonClientDpiScaling)
			enableNonClientDpiScaling(hWnd);
	}

	Nat windowDpi(HWND hWnd) {
		if (dpiMode == dpiMonitor && getDpiForWindow) {
			return getDpiForWindow(hWnd);
		} else if (dpiMode == dpiSystem && getDpiForSystem) {
			return getDpiForSystem();
		} else {
			return defaultDpi;
		}
	}

	int dpiSystemMetrics(int index, Nat dpi) {
		if (getSystemMetricsForDpi)
			return getSystemMetricsForDpi(index, dpi);
		else
			return GetSystemMetrics(index);
	}

	BOOL dpiSystemParametersInfo(UINT action, UINT param, void *data, UINT winIni, UINT dpi) {
		if (systemParametersInfoDpi)
			return systemParametersInfoDpi(action, param, data, winIni, dpi);
		else
			return SystemParametersInfo(action, param, data, winIni);
	}

	BOOL dpiAdjustWindowRectEx(RECT *rect, DWORD style, bool menu, DWORD exStyle, Nat dpi) {
		if (adjustWindowRectExForDpi)
			return adjustWindowRectExForDpi(rect, style, menu, exStyle, dpi);
		else
			return AdjustWindowRectEx(rect, style, menu, exStyle);
	}

	Float dpiScale(Nat dpi) {
		return Float(dpi) / Float(defaultDpi);
	}

	Float dpiScaleInv(Nat dpi) {
		return Float(defaultDpi) / Float(dpi);
	}

	Point dpiToPx(Nat dpi, Point pt) {
		return pt * dpiScale(dpi);
	}

	Size dpiToPx(Nat dpi, Size size) {
		return size * dpiScale(dpi);
	}

	Rect dpiToPx(Nat dpi, Rect rect) {
		Float scale = dpiScale(dpi);
		rect.p0 *= scale;
		rect.p1 *= scale;
		return rect;
	}

	Point dpiFromPx(Nat dpi, Point pt) {
		return pt * dpiScaleInv(dpi);
	}

	Size dpiFromPx(Nat dpi, Size size) {
		return size * dpiScaleInv(dpi);
	}

	Rect dpiFromPx(Nat dpi, Rect rect) {
		Float scale = dpiScaleInv(dpi);
		rect.p0 *= scale;
		rect.p1 *= scale;
		return rect;
	}

}

#endif