diff options
| author | Pietro Gagliardi <[email protected]> | 2014-08-30 23:02:02 -0400 |
|---|---|---|
| committer | Pietro Gagliardi <[email protected]> | 2014-08-30 23:02:02 -0400 |
| commit | 77bf566ebbcb62acd4d08d905d9542d6ff9b6b80 (patch) | |
| tree | eeb8e72bc3bf57f5be7f0c0af4319189ac6de838 /uitask_windows.c | |
| parent | 155899c65ed32245e2ccad4197a10c77017d835b (diff) | |
...in with the new.
Diffstat (limited to 'uitask_windows.c')
| -rw-r--r-- | uitask_windows.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/uitask_windows.c b/uitask_windows.c new file mode 100644 index 0000000..dec6ed2 --- /dev/null +++ b/uitask_windows.c @@ -0,0 +1,167 @@ +// 17 july 2014 + +#include "winapi_windows.h" +#include "_cgo_export.h" + +// note that this includes the terminating '\0' +// this also assumes WC_TABCONTROL is longer than areaWindowClass +#define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0]) + +void uimsgloop_area(HWND active, HWND focus, MSG *msg) +{ + MSG copy; + + copy = *msg; + switch (copy.message) { + case WM_KEYDOWN: + case WM_SYSKEYDOWN: // Alt+[anything] and F10 send these instead + copy.message = msgAreaKeyDown; + break; + case WM_KEYUP: + case WM_SYSKEYUP: + copy.message = msgAreaKeyUp; + break; + default: + goto notkey; + } + // if we handled the key, don't do the default behavior + // don't call TranslateMessage(); we do our own keyboard handling + if (DispatchMessage(©) != FALSE) + return; +notkey: + if (IsDialogMessage(active, msg) != 0) + return; + DispatchMessage(msg); +} + +void uimsgloop_tab(HWND active, HWND focus, MSG *msg) +{ + BOOL hasChildren; + BOOL idm; + + // THIS BIT IS IMPORTANT: if the current tab has no children, then there will be no children left in the dialog to tab to, and IsDialogMessageW() will loop forever + hasChildren = SendMessageW(focus, msgTabCurrentTabHasChildren, 0, 0); + if (hasChildren) + tabEnterChildren(focus); + idm = IsDialogMessageW(active, msg); + if (hasChildren) + tabLeaveChildren(focus); + if (idm != 0) + return; + TranslateMessage(msg); + DispatchMessage(msg); +} + +void uimsgloop_else(MSG *msg) +{ + TranslateMessage(msg); + DispatchMessage(msg); +} + +void uimsgloop(void) +{ + MSG msg; + int res; + HWND active, focus; + WCHAR classchk[NCLASSNAME]; + BOOL dodlgmessage; + + for (;;) { + SetLastError(0); + res = GetMessageW(&msg, NULL, 0, 0); + if (res < 0) + xpanic("error calling GetMessage()", GetLastError()); + if (res == 0) // WM_QUIT + break; + active = GetActiveWindow(); + if (active == NULL) { + uimsgloop_else(&msg); + continue; + } + + // bit of logic involved here: + // we don't want dialog messages passed into Areas, so we don't call IsDialogMessageW() there + // as for Tabs, we can't have both WS_TABSTOP and WS_EX_CONTROLPARENT set at the same time, so we hotswap the two styles to get the behavior we want + // theoretically we could use the class atom to avoid a wcscmp() + // however, raymond chen advises against this - http://blogs.msdn.com/b/oldnewthing/archive/2004/10/11/240744.aspx (and we're not in control of the Tab class, before you say anything) + // we could also theoretically just send msgAreaDefocuses directly, but what DefWindowProc() does to a WM_APP message is undocumented + focus = GetFocus(); + if (focus != NULL) { + if (GetClassNameW(focus, classchk, NCLASSNAME) == 0) + xpanic("error getting name of focused window class for Area check", GetLastError()); + if (_wcsicmp(classchk, areaWindowClass) == 0) { + uimsgloop_area(active, focus, &msg); + continue; + } else if (_wcsicmp(classchk, WC_TABCONTROL) == 0) { + uimsgloop_tab(active, focus, &msg); + continue; + } + // else fall through + } + + if (IsDialogMessage(active, &msg) != 0) + continue; + uimsgloop_else(&msg); + } +} + +void issue(void *request) +{ + SetLastError(0); + if (PostMessageW(msgwin, msgRequest, 0, (LPARAM) request) == 0) + xpanic("error issuing request", GetLastError()); +} + +HWND msgwin; + +#define msgwinclass L"gouimsgwin" + +static LRESULT CALLBACK msgwinproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT shared; + size_t i; + + if (sharedWndProc(hwnd, uMsg, wParam, lParam, &shared)) + return shared; + switch (uMsg) { + case msgRequest: + doissue((void *) lParam); + return 0; + case msgOpenFileDone: + finishOpenFile((WCHAR *) wParam, (void *) lParam); + return 0; + default: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + xmissedmsg("message-only", "msgwinproc()", uMsg); + return 0; // unreachable +} + +DWORD makemsgwin(char **errmsg) +{ + WNDCLASSW wc; + + ZeroMemory(&wc, sizeof (WNDCLASSW)); + wc.lpfnWndProc = msgwinproc; + wc.hInstance = hInstance; + wc.hIcon = hDefaultIcon; + wc.hCursor = hArrowCursor; + wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); + wc.lpszClassName = msgwinclass; + if (RegisterClassW(&wc) == 0) { + *errmsg = "error registering message-only window classs"; + return GetLastError(); + } + msgwin = CreateWindowExW( + 0, + msgwinclass, L"package ui message-only window", + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + HWND_MESSAGE, NULL, hInstance, NULL); + if (msgwin == NULL) { + *errmsg = "error creating message-only window"; + return GetLastError(); + } + return 0; +} |
