aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/windows/main.cpp
blob: eb6d84921d2773c23680c847b508ac5a8d37985b (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
// 6 april 2015
#include "uipriv_windows.hpp"

static HHOOK filter;

static LRESULT CALLBACK filterProc(int code, WPARAM wParam, LPARAM lParam)
{
	MSG *msg = (MSG *) lParam;

	if (code < 0)
		goto callNext;

	if (areaFilter(msg))		// don't continue to our IsDialogMessage() hack if the area handled it
		goto discard;

	// TODO IsDialogMessage() hack here

	// otherwise keep going
	goto callNext;

discard:
	// we handled it; discard the message so the dialog manager doesn't see it
	return 1;

callNext:
	return CallNextHookEx(filter, code, wParam, lParam);
}

int registerMessageFilter(void)
{
	filter = SetWindowsHookExW(WH_MSGFILTER,
		filterProc,
		hInstance,
		GetCurrentThreadId());
	return filter != NULL;
}

void unregisterMessageFilter(void)
{
	if (UnhookWindowsHookEx(filter) == 0)
		logLastError(L"error unregistering libui message filter");
}

// LONGTERM http://blogs.msdn.com/b/oldnewthing/archive/2005/04/08/406509.aspx when adding accelerators, TranslateAccelerators() before IsDialogMessage()

static void processMessage(MSG *msg)
{
	HWND correctParent;

	if (msg->hwnd != NULL)
		correctParent = parentToplevel(msg->hwnd);
	else		// just to be safe
		correctParent = GetActiveWindow();
	if (correctParent != NULL)
		// this calls our mesage filter above for us
		if (IsDialogMessage(correctParent, msg) != 0)
			return;
	TranslateMessage(msg);
	DispatchMessageW(msg);
}

static int waitMessage(MSG *msg)
{
	int res;

	res = GetMessageW(msg, NULL, 0, 0);
	if (res < 0) {
		logLastError(L"error calling GetMessage()");
		return 0;		// bail out on error
	}
	return res != 0;		// returns false on WM_QUIT
}

void uiMain(void)
{
	while (uiMainStep(1))
		;
}

void uiMainSteps(void)
{
	// don't need to do anything here
}

static int peekMessage(MSG *msg)
{
	BOOL res;

	res = PeekMessageW(msg, NULL, 0, 0, PM_REMOVE);
	if (res == 0)
		return 2;		// no message available
	if (msg->message != WM_QUIT)
		return 1;		// a message
	return 0;			// WM_QUIT
}

int uiMainStep(int wait)
{
	MSG msg;

	if (wait) {
		if (!waitMessage(&msg))
			return 0;
		processMessage(&msg);
		return 1;
	}

	// don't wait for a message
	switch (peekMessage(&msg)) {
	case 0:		// quit
		// TODO PostQuitMessage() again?
		return 0;
	case 1:		// process a message
		processMessage(&msg);
		// fall out to the case for no message
	}
	return 1;		// no message
}

void uiQuit(void)
{
	PostQuitMessage(0);
}

void uiQueueMain(void (*f)(void *data), void *data)
{
	if (PostMessageW(utilWindow, msgQueued, (WPARAM) f, (LPARAM) data) == 0)
		// LONGTERM this is likely not safe to call across threads (allocates memory)
		logLastError(L"error queueing function to run on main thread");
}