aboutsummaryrefslogtreecommitdiffhomepage
path: root/win32/PlatWin.h
blob: 2ffc4a5fb85829e9d603d4b8661d08e0461be23a (plain)
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
// Scintilla source code edit control
/** @file PlatWin.h
 ** Implementation of platform facilities on Windows.
 **/
// Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#ifndef PLATWIN_H
#define PLATWIN_H

namespace Scintilla::Internal {

#ifndef USER_DEFAULT_SCREEN_DPI
#define USER_DEFAULT_SCREEN_DPI		96
#endif
constexpr FLOAT dpiDefault = USER_DEFAULT_SCREEN_DPI;

// Used for defining font size with LOGFONT
constexpr int pointsPerInch = 72;

constexpr UINT codePageWindowsLatin = 1252;

extern void Platform_Initialise(void *hInstance) noexcept;

extern void Platform_Finalise(bool fromDllMain) noexcept;

constexpr RECT RectFromPRectangle(PRectangle prc) noexcept {
	const RECT rc = { static_cast<LONG>(prc.left), static_cast<LONG>(prc.top),
		static_cast<LONG>(prc.right), static_cast<LONG>(prc.bottom) };
	return rc;
}

constexpr PRectangle PRectangleFromRECT(RECT rc) noexcept {
	return PRectangle::FromInts(rc.left, rc.top, rc.right, rc.bottom);
}

constexpr POINT POINTFromPoint(Point pt) noexcept {
	return POINT{ static_cast<LONG>(pt.x), static_cast<LONG>(pt.y) };
}

constexpr Point PointFromPOINT(POINT pt) noexcept {
	return Point::FromInts(pt.x, pt.y);
}

constexpr SIZE SizeOfRect(RECT rc) noexcept {
	return { rc.right - rc.left, rc.bottom - rc.top };
}

ColourRGBA ColourFromSys(int nIndex) noexcept;

constexpr HWND HwndFromWindowID(WindowID wid) noexcept {
	return static_cast<HWND>(wid);
}

inline HWND HwndFromWindow(const Window &w) noexcept {
	return HwndFromWindowID(w.GetID());
}

extern HINSTANCE hinstPlatformRes;

UINT CodePageFromCharSet(CharacterSet characterSet, UINT documentCodePage) noexcept;

void *PointerFromWindow(HWND hWnd) noexcept;
void SetWindowPointer(HWND hWnd, void *ptr) noexcept;

HMONITOR MonitorFromWindowHandleScaling(HWND hWnd) noexcept;

UINT DpiForWindow(WindowID wid) noexcept;
float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;

int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;

void AdjustWindowRectForDpi(LPRECT lpRect, DWORD dwStyle, UINT dpi) noexcept;

HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept;

// Encapsulate WM_PAINT handling so that EndPaint is always called even with unexpected returns or exceptions.
struct Painter {
	HWND hWnd{};
	PAINTSTRUCT ps{};
	explicit Painter(HWND hWnd_) noexcept : hWnd(hWnd_) {
		::BeginPaint(hWnd, &ps);
	}
	~Painter() {
		::EndPaint(hWnd, &ps);
	}
};

class MouseWheelDelta {
	int wheelDelta = 0;
public:
	bool Accumulate(WPARAM wParam) noexcept {
		wheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
		return std::abs(wheelDelta) >= WHEEL_DELTA;
	}
	int Actions() noexcept {
		const int actions = wheelDelta / WHEEL_DELTA;
		wheelDelta = wheelDelta % WHEEL_DELTA;
		return actions;
	}
};

// Both GDI and DirectWrite can produce a HFONT for use in list boxes
struct FontWin : public Font {
	[[nodiscard]] virtual HFONT HFont() const noexcept = 0;
	[[nodiscard]] virtual std::unique_ptr<FontWin> Duplicate() const = 0;
	[[nodiscard]] virtual CharacterSet GetCharacterSet() const noexcept = 0;
};

// Buffer to hold strings and string position arrays without always allocating on heap.
// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer
// when less than safe size otherwise allocate on heap and free automatically.
template<typename T, int lengthStandard>
class VarBuffer {
	T bufferStandard[lengthStandard];
public:
	T *buffer;
	explicit VarBuffer(size_t length) : buffer(nullptr) {
		if (length > lengthStandard) {
			buffer = new T[length];
		} else {
			buffer = bufferStandard;
		}
	}
	// Deleted so VarBuffer objects can not be copied.
	VarBuffer(const VarBuffer &) = delete;
	VarBuffer(VarBuffer &&) = delete;
	VarBuffer &operator=(const VarBuffer &) = delete;
	VarBuffer &operator=(VarBuffer &&) = delete;

	~VarBuffer() noexcept {
		if (buffer != bufferStandard) {
			delete[]buffer;
			buffer = nullptr;
		}
	}
};

constexpr int stackBufferLength = 400;
class TextWide : public VarBuffer<wchar_t, stackBufferLength> {
public:
	int tlen;	// Using int instead of size_t as most Win32 APIs take int.
	TextWide(std::string_view text, int codePage) :
		VarBuffer<wchar_t, stackBufferLength>(text.length()) {
		if (codePage == CpUtf8) {
			tlen = static_cast<int>(UTF16FromUTF8(text, buffer, text.length()));
		} else {
			// Support Asian string display in 9x English
			tlen = ::MultiByteToWideChar(codePage, 0, text.data(), static_cast<int>(text.length()),
				buffer, static_cast<int>(text.length()));
		}
	}
	[[nodiscard]] std::wstring_view AsView() const noexcept {
		return std::wstring_view(buffer, tlen);
	}
};
using TextPositions = VarBuffer<XYPOSITION, stackBufferLength>;

// Manage the lifetime of a memory HBITMAP and its HDC so there are no leaks.
class GDIBitMap {
	HDC hdc{};
	HBITMAP hbm{};
	HBITMAP hbmOriginal{};

public:
	GDIBitMap() noexcept = default;
	// Deleted so GDIBitMap objects can not be copied.
	GDIBitMap(const GDIBitMap &) = delete;
	GDIBitMap(GDIBitMap &&) = delete;
	// Move would be OK but not needed yet
	GDIBitMap &operator=(const GDIBitMap &) = delete;
	GDIBitMap &operator=(GDIBitMap &&) = delete;
	~GDIBitMap() noexcept;

	void Create(HDC hdcBase, int width, int height, DWORD **pixels) noexcept;
	void Release() noexcept;
	HBITMAP Extract() noexcept;

	[[nodiscard]] HDC DC() const noexcept {
		return hdc;
	}
	[[nodiscard]] explicit operator bool() const noexcept {
		return hdc && hbm;
	}
};

}

#endif