summaryrefslogtreecommitdiff
path: root/newctrl/common_windows.c
blob: b30b132d356923ae5469b46b80af76462d3b5a7e (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
// 17 july 2014

#include "winapi_windows.h"
#include "_cgo_export.h"

LRESULT getWindowTextLen(HWND hwnd)
{
	return SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
}

void getWindowText(HWND hwnd, WPARAM n, LPWSTR buf)
{
	SetLastError(0);
	if (SendMessageW(hwnd, WM_GETTEXT, n + 1, (LPARAM) buf) != (LRESULT) n)
		xpanic("WM_GETTEXT did not copy the correct number of characters out", GetLastError());
}

void setWindowText(HWND hwnd, LPWSTR text)
{
	switch (SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM) text)) {
	case FALSE:
		xpanic("WM_SETTEXT failed", GetLastError());
	}
}

void updateWindow(HWND hwnd)
{
	if (UpdateWindow(hwnd) == 0)
		xpanic("error calling UpdateWindow()", GetLastError());
}

void *getWindowData(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
	CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
	void *data;

	data = (void *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
	if (data == NULL) {
		// the lpParam is available during WM_NCCREATE and WM_CREATE
		if (uMsg == WM_NCCREATE)
			SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams));
		// act as if we're not ready yet, even during WM_NCCREATE (nothing important to the switch statement below happens here anyway)
		*lResult = DefWindowProcW(hwnd, uMsg, wParam, lParam);
	}
	return data;
}

/*
all container windows (including the message-only window, hence this is not in container_windows.c) have to call the sharedWndProc() to ensure messages go in the right place and control colors are handled properly
*/

/*
all controls that have events receive the events themselves through subclasses
to do this, all container windows (including the message-only window; see http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q104069) forward WM_COMMAND to each control with this function, WM_NOTIFY with forwardNotify, etc.
*/
static LRESULT forwardCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	HWND control = (HWND) lParam;

	// don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
	if (control != NULL && IsChild(msgwin, control) == 0)
		return SendMessageW(control, msgCOMMAND, wParam, lParam);
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

static LRESULT forwardNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	NMHDR *nmhdr = (NMHDR *) lParam;
	HWND control = nmhdr->hwndFrom;

	// don't generate an event if the control (if there is one) is unparented (a child of the message-only window)
	if (control != NULL && IsChild(msgwin, control) == 0)
		return SendMessageW(control, msgNOTIFY, wParam, lParam);
	return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}

BOOL sharedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{
	switch (uMsg) {
	case WM_COMMAND:
		*lResult = forwardCommand(hwnd, uMsg, wParam, lParam);
		return TRUE;
	case WM_NOTIFY:
		*lResult = forwardNotify(hwnd, uMsg, wParam, lParam);
		return TRUE;
	case WM_CTLCOLORSTATIC:
	case WM_CTLCOLORBTN:
		if (SetBkMode((HDC) wParam, TRANSPARENT) == 0)
			xpanic("error setting transparent background mode to Labels", GetLastError());
		paintControlBackground((HWND) lParam, (HDC) wParam);
		*lResult = (LRESULT) hollowBrush;
		return TRUE;
	}
	return FALSE;
}

void paintControlBackground(HWND hwnd, HDC dc)
{
	HWND parent;
	RECT r;
	POINT p;
	int saved;
	WCHAR classname[128] = L"";		// more than enough to avoid collisions

	parent = hwnd;
	for (;;) {
		parent = GetParent(parent);
		if (parent == NULL)
			xpanic("error getting parent container of control in paintControlBackground()", GetLastError());
		// wine sends these messages early, yay...
		if (parent == msgwin)
			return;
		parent = GetParent(parent);
		if (parent == NULL)
			xpanic("error getting parent control of control in paintControlBackground()", GetLastError());
		if (parent == msgwin)
			return;
		if (GetClassNameW(parent, classname, 128) == 0)
			xpanic("error getting name of focused window class in paintControlBackground()", GetLastError());
		// skip container and groupboxes
		if (_wcsicmp(classname, containerclass) != 0)		// container
			if (_wcsicmp(classname, L"button") != 0)		// groupbox
				break;
	}
	if (GetWindowRect(hwnd, &r) == 0)
		xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
	// the above is a window rect; convert to client rect
	p.x = r.left;
	p.y = r.top;
	if (ScreenToClient(parent, &p) == 0)
		xpanic("error getting client origin of control in paintControlBackground()", GetLastError());
	saved = SaveDC(dc);
	if (saved == 0)
		xpanic("error saving DC info in paintControlBackground()", GetLastError());
	if (SetWindowOrgEx(dc, p.x, p.y, NULL) == 0)
		xpanic("error moving window origin in paintControlBackground()", GetLastError());
	SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT);
	if (RestoreDC(dc, saved) == 0)
		xpanic("error restoring DC info in paintControlBackground()", GetLastError());
}