diff --git a/new/container_windows.c b/new/container_windows.c index b389e70..d1bc9c6 100644 --- a/new/container_windows.c +++ b/new/container_windows.c @@ -1,6 +1,11 @@ // 7 april 2015 #include "uipriv_windows.h" +// TODOs +// - [12:24] There's flickering between tabs +// - with CTLCOLOR handler: [12:24] And setting the button text blanked out the entire GUI until I ran my mouse over the elements / [12:25] https://dl.dropboxusercontent.com/u/15144168/GUI%20stuff.png +// - without CTLCOLOR handler: [12:33] If I hide the stack, then show it, it looks like it's drawing duplicate buttons underneath + /* 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 */ @@ -30,6 +35,42 @@ static LRESULT forwardNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return DefWindowProcW(hwnd, uMsg, wParam, lParam); } +static void paintControlBackground(HWND hwnd, HDC dc) +{ + HWND parent; + RECT r; + POINT pOrig; + DWORD le; + + parent = hwnd; + for (;;) { + parent = GetParent(parent); + if (parent == NULL) + logLastError("error getting parent control of control in paintControlBackground()"); + // wine sends these messages early, yay... + if (parent == initialParent) + return; + // skip groupboxes; they're (supposed to be) transparent + if (windowClassOf(parent, L"button", NULL) != 0) + break; + } + if (GetWindowRect(hwnd, &r) == 0) + logLastError("error getting control's window rect in paintControlBackground()"); + // the above is a window rect in screen coordinates; convert to client rect + SetLastError(0); + if (MapWindowRect(NULL, parent, &r) == 0) { + le = GetLastError(); + SetLastError(le); // just to be safe + if (le != 0) + logLastError("error getting client origin of control in paintControlBackground()"); + } + if (SetWindowOrgEx(dc, r.left, r.top, &pOrig) == 0) + logLastError("error moving window origin in paintControlBackground()"); + SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT); + if (SetWindowOrgEx(dc, pOrig.x, pOrig.y, NULL) == 0) + logLastError("error resetting window origin in paintControlBackground()"); +} + BOOL sharedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) { switch (uMsg) { @@ -39,19 +80,19 @@ BOOL sharedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * case WM_NOTIFY: *lResult = forwardNotify(hwnd, uMsg, wParam, lParam); return TRUE; -/*TODO case WM_CTLCOLORSTATIC: + case WM_CTLCOLORSTATIC: case WM_CTLCOLORBTN: - // read-only TextFields and Textboxes are exempt +/*TODO // read-only TextFields and Textboxes are exempt // this is because read-only edit controls count under WM_CTLCOLORSTATIC if (windowClassOf((HWND) lParam, L"edit", NULL) == 0) if (textfieldReadOnly((HWND) lParam)) return FALSE; - if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - xpanic("error setting transparent background mode to Labels", GetLastError()); +*/ if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) + logLastError("error setting transparent background mode to controls in sharedWndProc()"); paintControlBackground((HWND) lParam, (HDC) wParam); *lResult = (LRESULT) hollowBrush; return TRUE; -*/ } + } return FALSE; } diff --git a/new/init_windows.c b/new/init_windows.c index 7ebe4e2..d0390be 100644 --- a/new/init_windows.c +++ b/new/init_windows.c @@ -6,6 +6,8 @@ int nCmdShow; HFONT hMessageFont; +HBRUSH hollowBrush; + struct uiInitError { char *msg; char failbuf[256]; @@ -97,6 +99,10 @@ const char *uiInit(uiInitOptions *o) if (ce != NULL) return loadLastError(ce); + hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); + if (hollowBrush == NULL) + return loadLastError("getting hollow brush"); + return NULL; } diff --git a/new/uipriv_windows.h b/new/uipriv_windows.h index a8cd429..54c0906 100644 --- a/new/uipriv_windows.h +++ b/new/uipriv_windows.h @@ -45,7 +45,10 @@ extern HRESULT logMemoryExhausted(const char *); extern HINSTANCE hInstance; extern int nCmdShow; extern HFONT hMessageFont; -extern HWND initialParent; +extern HBRUSH hollowBrush; + +// util_windows.c +extern int windowClassOf(HWND, ...); // text_windows.c extern WCHAR *toUTF16(const char *); @@ -66,4 +69,5 @@ extern const char *initCommonControls(void); extern ATOM registerWindowClass(HICON, HCURSOR); // initparent_windows.c +extern HWND initialParent; extern const char *initInitialParent(HICON, HCURSOR); diff --git a/new/util_windows.c b/new/util_windows.c index e3332be..93b32d8 100644 --- a/new/util_windows.c +++ b/new/util_windows.c @@ -38,3 +38,36 @@ intmax_t uiWindowsWindowTextWidth(HWND hwnd) return size.cx; } + +// this is a helper function that takes the logic of determining window classes and puts it all in one place +// there are a number of places where we need to know what window class an arbitrary handle has +// theoretically we could use the class atom to avoid a _wcsicmp() +// 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) +// usage: windowClassOf(hwnd, L"class 1", L"class 2", ..., NULL) +int windowClassOf(HWND hwnd, ...) +{ +// MSDN says 256 is the maximum length of a class name; add a few characters just to be safe (because it doesn't say whether this includes the terminating null character) +#define maxClassName 260 + WCHAR classname[maxClassName + 1]; + va_list ap; + WCHAR *curname; + int i; + + if (GetClassNameW(hwnd, classname, maxClassName) == 0) + logLastError("error getting name of window class in windowClassOf()"); + va_start(ap, hwnd); + i = 0; + for (;;) { + curname = va_arg(ap, WCHAR *); + if (curname == NULL) + break; + if (_wcsicmp(classname, curname) == 0) { + va_end(ap); + return i; + } + i++; + } + // no match + va_end(ap); + return -1; +}