diff options
Diffstat (limited to 'new/windows')
| -rw-r--r-- | new/windows/GNUmakeinc.mk | 33 | ||||
| -rw-r--r-- | new/windows/alloc.c | 49 | ||||
| -rw-r--r-- | new/windows/button.c | 112 | ||||
| -rw-r--r-- | new/windows/checkbox.c | 129 | ||||
| -rw-r--r-- | new/windows/comctl32.c | 105 | ||||
| -rw-r--r-- | new/windows/debug.c | 111 | ||||
| -rw-r--r-- | new/windows/entry.c | 69 | ||||
| -rw-r--r-- | new/windows/init.c | 112 | ||||
| -rw-r--r-- | new/windows/label.c | 73 | ||||
| -rw-r--r-- | new/windows/main.c | 56 | ||||
| -rw-r--r-- | new/windows/newcontrol.c | 237 | ||||
| -rw-r--r-- | new/windows/parent.c | 268 | ||||
| -rw-r--r-- | new/windows/tab.c | 190 | ||||
| -rw-r--r-- | new/windows/text.c | 55 | ||||
| -rw-r--r-- | new/windows/uipriv_windows.h | 69 | ||||
| -rw-r--r-- | new/windows/util.c | 73 | ||||
| -rw-r--r-- | new/windows/window.c | 216 |
17 files changed, 0 insertions, 1957 deletions
diff --git a/new/windows/GNUmakeinc.mk b/new/windows/GNUmakeinc.mk deleted file mode 100644 index 494b8e3..0000000 --- a/new/windows/GNUmakeinc.mk +++ /dev/null @@ -1,33 +0,0 @@ -OSCFILES = \ - alloc.c \ - button.c \ - checkbox.c \ - comctl32.c \ - debug.c \ - entry.c \ - init.c \ - label.c \ - main.c \ - newcontrol.c \ - parent.c \ - tab.c \ - text.c \ - util.c \ - window.c - -xLDFLAGS += \ - -luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32 -lole32 -loleaut32 -loleacc -luuid - -OUT = new.exe - -ifeq ($(ARCH),64) - CC = x86_64-w64-mingw32-gcc - RC = x86_64-w64-mingw32-windres - xCFLAGS += -m64 - xLDFLAGS += -m64 -else - CC = i686-w64-mingw32-gcc - RC = i686-w64-mingw32-windres - xCFLAGS += -m32 - xLDFLAGS += -m32 -endif diff --git a/new/windows/alloc.c b/new/windows/alloc.c deleted file mode 100644 index 147c90d..0000000 --- a/new/windows/alloc.c +++ /dev/null @@ -1,49 +0,0 @@ -// 4 december 2014 -#include "uipriv_windows.h" - -// wrappers for allocator of choice -// panics on memory exhausted, undefined on heap corruption or other unreliably-detected malady (see http://stackoverflow.com/questions/28761680/is-there-a-windows-api-memory-allocator-deallocator-i-can-use-that-will-just-giv) -// new memory is set to zero -// passing NULL to tableRealloc() acts like tableAlloc() -// passing NULL to tableFree() is a no-op - -void *uiAlloc(size_t size, const char *type) -{ - void *out; - - out = malloc(size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiAlloc() allocating %s\n", type); - abort(); - } - ZeroMemory(out, size); - if (options.debugLogAllocations) - fprintf(stderr, "%p alloc %s\n", out, type); - return out; -} - -void *uiRealloc(void *p, size_t size, const char *type) -{ - void *out; - - if (p == NULL) - return uiAlloc(size, type); - out = realloc(p, size); - if (out == NULL) { - fprintf(stderr, "memory exhausted in uiRealloc() reallocating %s\n", type); - abort(); - } - // TODO zero the extra memory - if (options.debugLogAllocations) - fprintf(stderr, "%p realloc %p\n", p, out); - return out; -} - -void uiFree(void *p) -{ - if (p == NULL) - return; - free(p); - if (options.debugLogAllocations) - fprintf(stderr, "%p free\n", p); -} diff --git a/new/windows/button.c b/new/windows/button.c deleted file mode 100644 index fd7afa3..0000000 --- a/new/windows/button.c +++ /dev/null @@ -1,112 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.h" - -struct button { - uiButton b; - void (*onClicked)(uiButton *, void *); - void *onClickedData; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - struct button *b = (struct button *) c; - - if (code != BN_CLICKED) - return FALSE; - (*(b->onClicked))(uiButton(b), b->onClickedData); - *lResult = 0; - return TRUE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct button *b = (struct button *) c; - - uiFree(b); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define buttonHeight 14 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - HWND hwnd; - SIZE size; - - hwnd = uiControlHWND(c); - - // try the comctl32 version 6 way - size.cx = 0; // explicitly ask for ideal size - size.cy = 0; - if (SendMessageW(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM) (&size)) != FALSE) { - *width = size.cx; - *height = size.cy; - return; - } - - // that didn't work; fall back to using Microsoft's metrics - // Microsoft says to use a fixed width for all buttons; this isn't good enough - // use the text width instead, with some edge padding - *width = uiWindowsWindowTextWidth(hwnd) + (2 * GetSystemMetrics(SM_CXEDGE)); - *height = uiDlgUnitsToY(buttonHeight, d->sys->baseY); -} - -static void defaultOnClicked(uiButton *b, void *data) -{ - // do nothing -} - -static char *getText(uiButton *b) -{ - return uiWindowsControlText(uiControl(b)); -} - -static void setText(uiButton *b, const char *text) -{ - uiWindowsControlSetText(uiControl(b), text); -} - -static void setOnClicked(uiButton *bb, void (*f)(uiButton *, void *), void *data) -{ - struct button *b = (struct button *) bb; - - b->onClicked = f; - b->onClickedData = data; -} - -uiButton *uiNewButton(const char *text) -{ - struct button *b; - uiWindowsNewControlParams p; - WCHAR *wtext; - - b = uiNew(struct button); - - p.dwExStyle = 0; - p.lpClassName = L"button"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - p.dwStyle = BS_PUSHBUTTON | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(b), &p); - uiFree(wtext); - - b->onClicked = defaultOnClicked; - - uiControl(b)->PreferredSize = preferredSize; - - uiButton(b)->Text = getText; - uiButton(b)->SetText = setText; - uiButton(b)->OnClicked = setOnClicked; - - return uiButton(b); -} diff --git a/new/windows/checkbox.c b/new/windows/checkbox.c deleted file mode 100644 index c1d5a6f..0000000 --- a/new/windows/checkbox.c +++ /dev/null @@ -1,129 +0,0 @@ -// 7 april 2015 -#include "uipriv_windows.h" - -struct checkbox { - uiCheckbox c; - void (*onToggled)(uiCheckbox *, void *); - void *onToggledData; -}; - -static BOOL onWM_COMMAND(uiControl *cc, WORD code, LRESULT *lResult) -{ - struct checkbox *c = (struct checkbox *) cc; - HWND hwnd; - WPARAM check; - - if (code != BN_CLICKED) - return FALSE; - - // we didn't use BS_AUTOCHECKBOX (see controls_windows.go) so we have to manage the check state ourselves - hwnd = uiControlHWND(uiControl(c)); - check = BST_CHECKED; - if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) - check = BST_UNCHECKED; - SendMessage(hwnd, BM_SETCHECK, check, 0); - - (*(c->onToggled))(uiCheckbox(c), c->onToggledData); - *lResult = 0; - return TRUE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *cc) -{ - struct checkbox *c = (struct checkbox *) cc; - - uiFree(c); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define checkboxHeight 10 -// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -#define checkboxXFromLeftOfBoxToLeftOfLabel 12 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiDlgUnitsToX(checkboxXFromLeftOfBoxToLeftOfLabel, d->sys->baseX) + uiWindowsWindowTextWidth(uiControlHWND(c)); - *height = uiDlgUnitsToY(checkboxHeight, d->sys->baseY); -} - -static void defaultOnToggled(uiCheckbox *c, void *data) -{ - // do nothing -} - -static char *getText(uiCheckbox *c) -{ - return uiWindowsControlText(uiControl(c)); -} - -static void setText(uiCheckbox *c, const char *text) -{ - uiWindowsControlSetText(uiControl(c), text); -} - -static void setOnToggled(uiCheckbox *cc, void (*f)(uiCheckbox *, void *), void *data) -{ - struct checkbox *c = (struct checkbox *) cc; - - c->onToggled = f; - c->onToggledData = data; -} - -static int getChecked(uiCheckbox *c) -{ - HWND hwnd; - - hwnd = uiControlHWND(uiControl(c)); - return SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED; -} - -static void setChecked(uiCheckbox *c, int checked) -{ - HWND hwnd; - WPARAM check; - - hwnd = uiControlHWND(uiControl(c)); - check = BST_CHECKED; - if (!checked) - check = BST_UNCHECKED; - SendMessage(hwnd, BM_SETCHECK, check, 0); -} - -uiCheckbox *uiNewCheckbox(const char *text) -{ - struct checkbox *c; - uiWindowsNewControlParams p; - WCHAR *wtext; - - c = uiNew(struct checkbox); - - p.dwExStyle = 0; - p.lpClassName = L"button"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - p.dwStyle = BS_CHECKBOX | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(c), &p); - uiFree(wtext); - - c->onToggled = defaultOnToggled; - - uiControl(c)->PreferredSize = preferredSize; - - uiCheckbox(c)->Text = getText; - uiCheckbox(c)->SetText = setText; - uiCheckbox(c)->OnToggled = setOnToggled; - uiCheckbox(c)->Checked = getChecked; - uiCheckbox(c)->SetChecked = setChecked; - - return uiCheckbox(c); -} diff --git a/new/windows/comctl32.c b/new/windows/comctl32.c deleted file mode 100644 index 93b3a27..0000000 --- a/new/windows/comctl32.c +++ /dev/null @@ -1,105 +0,0 @@ -// 17 july 2014 -#include "uipriv_windows.h" - -static ULONG_PTR comctlManifestCookie; -static HMODULE comctl32; - -// these are listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason -BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); -BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); -LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); - -#define wantedICCClasses ( \ - ICC_STANDARD_CLASSES | /* user32.dll controls */ \ - ICC_PROGRESS_CLASS | /* progress bars */ \ - ICC_TAB_CLASSES | /* tabs */ \ - ICC_LISTVIEW_CLASSES | /* table headers */ \ - ICC_UPDOWN_CLASS | /* spinboxes */ \ - 0) - -// note that this is an 8-bit character string we're writing; see the encoding clause -static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\n"; - -/* -Windows requires a manifest file to enable Common Controls version 6. -The only way to not require an external manifest is to synthesize the manifest ourselves. -We can use the activation context API to load it at runtime. -References: -- http://stackoverflow.com/questions/4308503/how-to-enable-visual-styles-without-a-manifest -- http://support.microsoft.com/kb/830033 -Because neither Go nor MinGW have ways to compile in resources like this (as far as I know), we have to do the work ourselves. -*/ -const char *initCommonControls(void) -{ - WCHAR temppath[MAX_PATH + 1]; - WCHAR filename[MAX_PATH + 1]; - HANDLE file; - DWORD nExpected, nGot; - ACTCTX actctx; - HANDLE ac; - INITCOMMONCONTROLSEX icc; - FARPROC f; - // this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason - BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX); - - if (GetTempPathW(MAX_PATH + 1, temppath) == 0) - return "getting temporary path for writing manifest file in initCommonControls()"; - if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0) - return "getting temporary filename for writing manifest file in initCommonControls()"; - file = CreateFileW(filename, GENERIC_WRITE, - 0, // don't share while writing - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (file == NULL) - return "creating manifest file in initCommonControls()"; - nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character) - SetLastError(0); // catch errorless short writes - if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0) - return "writing manifest file in initCommonControls()"; - if (nGot != nExpected) { - DWORD lasterr; - - lasterr = GetLastError(); - if (lasterr == 0) - return "writing entire manifest file (short write) without error code in initCommonControls()"; - return "writing entire manifest file (short write) in initCommonControls()"; - } - if (CloseHandle(file) == 0) - return "closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context) in initCommonControls()"; - - ZeroMemory(&actctx, sizeof (ACTCTX)); - actctx.cbSize = sizeof (ACTCTX); - actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT; - actctx.lpSource = filename; - ac = CreateActCtx(&actctx); - if (ac == INVALID_HANDLE_VALUE) - return "creating activation context for synthesized manifest file in initCommonControls()"; - if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE) - return "activating activation context for synthesized manifest file in initCommonControls()"; - - ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); - icc.dwSize = sizeof (INITCOMMONCONTROLSEX); - icc.dwICC = wantedICCClasses; - - comctl32 = LoadLibraryW(L"comctl32.dll"); - if (comctl32 == NULL) - return "loading comctl32.dll in initCommonControls()"; - - // GetProcAddress() only takes a multibyte string -#define LOAD(fn) f = GetProcAddress(comctl32, fn); \ - if (f == NULL) \ - return "loading " fn "() in initCommonControls()"; - - LOAD("InitCommonControlsEx"); - ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f; - LOAD("SetWindowSubclass"); - fv_SetWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR)) f; - LOAD("RemoveWindowSubclass"); - fv_RemoveWindowSubclass = (BOOL (*WINAPI)(HWND, SUBCLASSPROC, UINT_PTR)) f; - LOAD("DefSubclassProc"); - fv_DefSubclassProc = (LRESULT (*WINAPI)(HWND, UINT, WPARAM, LPARAM)) f; - - if ((*ficc)(&icc) == FALSE) - return "initializing Common Controls (comctl32.dll) in initCommonControls()"; - - return NULL; -} diff --git a/new/windows/debug.c b/new/windows/debug.c deleted file mode 100644 index bc84b63..0000000 --- a/new/windows/debug.c +++ /dev/null @@ -1,111 +0,0 @@ -// 25 february 2015 -#include "uipriv_windows.h" - -// uncomment the following line to enable debug messages -#define tableDebug -// uncomment the following line to halt on a debug message -#define tableDebugStop - -#ifdef tableDebug - -#include <stdio.h> - -HRESULT logLastError(const char *context) -{ - DWORD le; - WCHAR *msg; - BOOL parenthesize = FALSE; - BOOL localFreeFailed = FALSE; - DWORD localFreeLastError; - - le = GetLastError(); - fprintf(stderr, "%s: ", context); - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&msg), 0, NULL) != 0) { - fprintf(stderr, "%S (", msg); - if (LocalFree(msg) != NULL) { - localFreeFailed = TRUE; - localFreeLastError = GetLastError(); - } - parenthesize = TRUE; - } - fprintf(stderr, "GetLastError() == %I32u", le); - if (parenthesize) - fprintf(stderr, ")"); - if (localFreeFailed) - fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError); - fprintf(stderr, "\n"); -#ifdef tableDebugStop - DebugBreak(); -#endif - SetLastError(le); - // a function does not have to set a last error - // if the last error we get is actually 0, then HRESULT_FROM_WIN32(0) will return S_OK (0 cast to an HRESULT, since 0 <= 0), which we don't want - // prevent this by returning E_FAIL, so the rest of the Table code doesn't barge onward - if (le == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(le); -} - -HRESULT logHRESULT(const char *context, HRESULT hr) -{ - WCHAR *msg; - BOOL parenthesize = FALSE; - BOOL localFreeFailed = FALSE; - DWORD localFreeLastError; - - fprintf(stderr, "%s: ", context); - // this isn't technically documented, but everyone does it, including Microsoft (see the implementation of _com_error::ErrorMessage() in a copy of comdef.h that comes with the Windows DDK) - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) hr, 0, (LPWSTR) (&msg), 0, NULL) != 0) { - fprintf(stderr, "%S (", msg); - if (LocalFree(msg) != NULL) { - localFreeFailed = TRUE; - localFreeLastError = GetLastError(); - } - parenthesize = TRUE; - } - fprintf(stderr, "HRESULT == 0x%I32X", hr); - if (parenthesize) - fprintf(stderr, ")"); - if (localFreeFailed) - fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError); - fprintf(stderr, "\n"); -#ifdef tableDebugStop - DebugBreak(); -#endif - return hr; -} - -HRESULT logMemoryExhausted(const char *reason) -{ - fprintf(stderr, "memory exhausted %s\n", reason); -#ifdef tableDebugStop - DebugBreak(); -#endif - return E_OUTOFMEMORY; -} - -#else - -HRESULT logLastError(const char *reason) -{ - DWORD le; - - le = GetLastError(); - // we shouldn't need to do this, but let's do this anyway just to be safe - SetLastError(le); - if (le == 0) - return E_FAIL; - return HRESULT_FROM_WIN32(le); -} - -HRESULT logHRESULT(const char *reason, HRESULT hr) -{ - return hr; -} - -HRESULT logMemoryExhausted(const char *reason) -{ - return E_OUTOFMEMORY; -} - -#endif diff --git a/new/windows/entry.c b/new/windows/entry.c deleted file mode 100644 index 22c108a..0000000 --- a/new/windows/entry.c +++ /dev/null @@ -1,69 +0,0 @@ -// 8 april 2015 -#include "uipriv_windows.h" - -struct entry { - uiEntry e; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct entry *e = (struct entry *) c; - - uiFree(e); -} - -// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ -#define entryHeight 14 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiDlgUnitsToX(entryWidth, d->sys->baseX); - *height = uiDlgUnitsToY(entryHeight, d->sys->baseY); -} - -static char *getText(uiEntry *e) -{ - return uiWindowsControlText(uiControl(e)); -} - -static void setText(uiEntry *e, const char *text) -{ - uiWindowsControlSetText(uiControl(e), text); -} - -uiEntry *uiNewEntry(void) -{ - struct entry *e; - uiWindowsNewControlParams p; - - e = uiNew(struct entry); - - p.dwExStyle = WS_EX_CLIENTEDGE; - p.lpClassName = L"edit"; - p.lpWindowName = L""; - p.dwStyle = ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(e), &p); - - uiControl(e)->PreferredSize = preferredSize; - - uiEntry(e)->Text = getText; - uiEntry(e)->SetText = setText; - - return uiEntry(e); -} diff --git a/new/windows/init.c b/new/windows/init.c deleted file mode 100644 index 9903934..0000000 --- a/new/windows/init.c +++ /dev/null @@ -1,112 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -HINSTANCE hInstance; -int nCmdShow; - -HFONT hMessageFont; - -HBRUSH hollowBrush; - -struct uiInitError { - char *msg; - char failbuf[256]; -}; - -#define initErrorFormat L"error %s: %s%sGetLastError() == %I32u%s" -#define initErrorArgs wmessage, sysmsg, beforele, le, afterle - -static const char *loadLastError(const char *message) -{ - WCHAR *sysmsg; - BOOL hassysmsg; - WCHAR *beforele; - WCHAR *afterle; - int n; - WCHAR *wmessage; - WCHAR *wstr; - const char *str; - DWORD le; - - le = GetLastError(); - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0) { - hassysmsg = TRUE; - beforele = L" ("; - afterle = L")"; - } else { - hassysmsg = FALSE; - sysmsg = L""; - beforele = L""; - afterle = L""; - } - wmessage = toUTF16(message); - n = _scwprintf(initErrorFormat, initErrorArgs); - wstr = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - snwprintf(wstr, n + 1, initErrorFormat, initErrorArgs); - str = toUTF8(wstr); - uiFree(wstr); - if (hassysmsg) - if (LocalFree(sysmsg) != NULL) - logLastError("error freeing system message in loadLastError()"); - uiFree(wmessage); - return str; -} - -uiInitOptions options; - -const char *uiInit(uiInitOptions *o) -{ - STARTUPINFOW si; - const char *ce; - HICON hDefaultIcon; - HCURSOR hDefaultCursor; - NONCLIENTMETRICSW ncm; - - options = *o; - - hInstance = GetModuleHandle(NULL); - if (hInstance == NULL) - return loadLastError("getting program HINSTANCE"); - - nCmdShow = SW_SHOWDEFAULT; - GetStartupInfoW(&si); - if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) - nCmdShow = si.wShowWindow; - - ce = initCommonControls(); - if (ce != NULL) - return loadLastError(ce); - - hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); - if (hDefaultIcon == NULL) - return loadLastError("loading default icon for window classes"); - hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); - if (hDefaultCursor == NULL) - return loadLastError("loading default cursor for window classes"); - - if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("registering uiWindow window class"); - - ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); - ncm.cbSize = sizeof (NONCLIENTMETRICSW); - if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) - return loadLastError("getting default fonts"); - hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); - if (hMessageFont == NULL) - return loadLastError("loading default messagebox font; this is the default UI font"); - - ce = initParent(hDefaultIcon, hDefaultCursor); - if (ce != NULL) - return loadLastError(ce); - - hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); - if (hollowBrush == NULL) - return loadLastError("getting hollow brush"); - - return NULL; -} - -void uiFreeInitError(const char *err) -{ - uiFree((void *) err); -} diff --git a/new/windows/label.c b/new/windows/label.c deleted file mode 100644 index 29c03f7..0000000 --- a/new/windows/label.c +++ /dev/null @@ -1,73 +0,0 @@ -// 11 april 2015 -#include "uipriv_windows.h" - -struct label { - uiLabel l; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct label *l = (struct label *) c; - - uiFree(l); -} - -// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define labelHeight 8 - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - *width = uiWindowsWindowTextWidth(uiControlHWND(c)); - *height = uiDlgUnitsToY(labelHeight, d->sys->baseY); -} - -static char *getText(uiLabel *l) -{ - return uiWindowsControlText(uiControl(l)); -} - -static void setText(uiLabel *l, const char *text) -{ - uiWindowsControlSetText(uiControl(l), text); -} - -uiLabel *uiNewLabel(const char *text) -{ - struct label *l; - uiWindowsNewControlParams p; - WCHAR *wtext; - - l = uiNew(struct label); - - p.dwExStyle = 0; - p.lpClassName = L"static"; - wtext = toUTF16(text); - p.lpWindowName = wtext; - // SS_LEFTNOWORDWRAP clips text past the end; SS_NOPREFIX avoids accelerator translation - // controls are vertically aligned to the top by default (thanks Xeek in irc.freenode.net/#winapi) - p.dwStyle = SS_LEFTNOWORDWRAP | SS_NOPREFIX; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(l), &p); - uiFree(wtext); - - uiControl(l)->PreferredSize = preferredSize; - - uiLabel(l)->Text = getText; - uiLabel(l)->SetText = setText; - - return uiLabel(l); -} diff --git a/new/windows/main.c b/new/windows/main.c deleted file mode 100644 index bd973b7..0000000 --- a/new/windows/main.c +++ /dev/null @@ -1,56 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -// #qo LDFLAGS: -luser32 -lkernel32 -lgdi32 -luxtheme -lmsimg32 -lcomdlg32 -lole32 -loleaut32 -loleacc -luuid - -static void uimsgloop_else(MSG *msg) -{ - TranslateMessage(msg); - DispatchMessage(msg); -} - -void uiMain(void) -{ - MSG msg; - int res; - HWND active, focus; - - for (;;) { - SetLastError(0); - res = GetMessageW(&msg, NULL, 0, 0); - if (res < 0) - logLastError("error calling GetMessage() in uiMain()"); - 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 - focus = GetFocus(); - if (focus != NULL) { -/*TODO switch (windowClassOf(focus, areaWindowClass, WC_TABCONTROLW, NULL)) { - case 0: // areaWindowClass - uimsgloop_area(active, focus, &msg); - continue; - case 1: // WC_TABCONTROLW - uimsgloop_tab(active, focus, &msg); - continue; - } - // else fall through -*/ } - - if (IsDialogMessage(active, &msg) != 0) - continue; - uimsgloop_else(&msg); - } -} - -void uiQuit(void) -{ - PostQuitMessage(0); -} diff --git a/new/windows/newcontrol.c b/new/windows/newcontrol.c deleted file mode 100644 index 565ec05..0000000 --- a/new/windows/newcontrol.c +++ /dev/null @@ -1,237 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -typedef struct singleHWND singleHWND; - -struct singleHWND { - HWND hwnd; - BOOL (*onWM_COMMAND)(uiControl *, WORD, LRESULT *); - BOOL (*onWM_NOTIFY)(uiControl *, NMHDR *, LRESULT *); - void (*onWM_DESTROY)(uiControl *); - uiParent *parent; - BOOL userHid; - BOOL containerHid; - BOOL userDisabled; - BOOL containerDisabled; -}; - -static void singleDestroy(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (DestroyWindow(s->hwnd) == 0) - logLastError("error destroying control in singleDestroy()"); - // the data structures are destroyed in the subclass procedure -} - -static uintptr_t singleHandle(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - return (uintptr_t) (s->hwnd); -} - -static void singleSetParent(uiControl *c, uiParent *parent) -{ - singleHWND *s = (singleHWND *) (c->Internal); - uiParent *oldparent; - HWND newParentHWND; - - oldparent = s->parent; - s->parent = parent; - newParentHWND = initialParent; - if (s->parent != NULL) - newParentHWND = uiParentHWND(s->parent); - if (SetParent(s->hwnd, newParentHWND) == NULL) - logLastError("error setting control parent in singleSetParent()"); - if (oldparent != NULL) - uiParentUpdate(oldparent); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (MoveWindow(s->hwnd, x, y, width, height, TRUE) == 0) - logLastError("error moving control in singleResize()"); -} - -static int singleVisible(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - if (s->userHid) - return 0; - return 1; -} - -static void singleShow(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userHid = FALSE; - if (!s->containerHid) { - ShowWindow(s->hwnd, SW_SHOW); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleHide(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userHid = TRUE; - ShowWindow(s->hwnd, SW_HIDE); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleContainerShow(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerHid = FALSE; - if (!s->userHid) { - ShowWindow(s->hwnd, SW_SHOW); - if (s->parent != NULL) - uiParentUpdate(s->parent); - } -} - -static void singleContainerHide(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerHid = TRUE; - ShowWindow(s->hwnd, SW_HIDE); - if (s->parent != NULL) - uiParentUpdate(s->parent); -} - -static void singleEnable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userDisabled = FALSE; - if (!s->containerDisabled) - EnableWindow(s->hwnd, TRUE); -} - -static void singleDisable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->userDisabled = TRUE; - EnableWindow(s->hwnd, FALSE); -} - -static void singleContainerEnable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerDisabled = FALSE; - if (!s->userDisabled) - EnableWindow(s->hwnd, TRUE); -} - -static void singleContainerDisable(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - - s->containerDisabled = TRUE; - EnableWindow(s->hwnd, FALSE); -} - -static LRESULT CALLBACK singleSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - uiControl *c = (uiControl *) dwRefData; - singleHWND *s = (singleHWND *) (c->Internal); - LRESULT lResult; - - switch (uMsg) { - case msgCOMMAND: - if ((*(s->onWM_COMMAND))(c, HIWORD(wParam), &lResult) != FALSE) - return lResult; - break; - case msgNOTIFY: - if ((*(s->onWM_NOTIFY))(c, (NMHDR *) lParam, &lResult) != FALSE) - return lResult; - break; - case WM_DESTROY: - (*(s->onWM_DESTROY))(c); - uiFree(s); - break; - case WM_NCDESTROY: - if ((*fv_RemoveWindowSubclass)(hwnd, singleSubclassProc, uIdSubclass) == FALSE) - logLastError("error removing Windows control subclass in singleSubclassProc()"); - break; - } - return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); -} - -void uiWindowsNewControl(uiControl *c, uiWindowsNewControlParams *p) -{ - singleHWND *s; - - s = uiNew(singleHWND); - s->hwnd = CreateWindowExW(p->dwExStyle, - p->lpClassName, p->lpWindowName, - p->dwStyle | WS_CHILD | WS_VISIBLE, - 0, 0, - // use a nonzero initial size just in case some control breaks with a zero initial size - 100, 100, - initialParent, NULL, p->hInstance, NULL); - if (s->hwnd == NULL) - logLastError("error creating control in uiWindowsNewControl()"); - s->onWM_COMMAND = p->onWM_COMMAND; - s->onWM_NOTIFY = p->onWM_NOTIFY; - s->onWM_DESTROY = p->onWM_DESTROY; - - c->Destroy = singleDestroy; - c->Handle = singleHandle; - c->SetParent = singleSetParent; - c->Resize = singleResize; - c->Visible = singleVisible; - c->Show = singleShow; - c->Hide = singleHide; - c->ContainerShow = singleContainerShow; - c->ContainerHide = singleContainerHide; - c->Enable = singleEnable; - c->Disable = singleDisable; - c->ContainerEnable = singleContainerEnable; - c->ContainerDisable = singleContainerDisable; - - if (p->useStandardControlFont) - SendMessageW(s->hwnd, WM_SETFONT, (WPARAM) hMessageFont, (LPARAM) TRUE); - - if ((*fv_SetWindowSubclass)(s->hwnd, singleSubclassProc, 0, (DWORD_PTR) c) == FALSE) - logLastError("error subclassing Windows control in uiWindowsNewControl()"); - - c->Internal = s; -} - -char *uiWindowsControlText(uiControl *c) -{ - singleHWND *s = (singleHWND *) (c->Internal); - WCHAR *wtext; - char *text; - - wtext = windowText(s->hwnd); - text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -void uiWindowsControlSetText(uiControl *c, const char *text) -{ - singleHWND *s = (singleHWND *) (c->Internal); - WCHAR *wtext; - - wtext = toUTF16(text); - if (SetWindowTextW(s->hwnd, wtext) == 0) - logLastError("error setting control text in uiWindowsControlSetText()"); - uiFree(wtext); -} diff --git a/new/windows/parent.c b/new/windows/parent.c deleted file mode 100644 index b3606d1..0000000 --- a/new/windows/parent.c +++ /dev/null @@ -1,268 +0,0 @@ -// 10 april 2015 -#include "uipriv_windows.h" - -// All controls in package ui are children of a window of this class. -// This keeps everything together, makes hiding controls en masse (tab page switching, for instance) easy, and makes the overall design cleaner. -// In addition, controls that are first created or don't have a parent are considered children of the "initial parent", which is also of this class. -// This parent is invisible, disabled, and should not be interacted with. - -// TODOs -// - wiith CTLCOLOR handler: [12:24] <ZeroOne> There's flickering between tabs -// - with CTLCOLOR handler: [12:24] <ZeroOne> And setting the button text blanked out the entire GUI until I ran my mouse over the elements / [12:25] <ZeroOne> https://dl.dropboxusercontent.com/u/15144168/GUI%20stuff.png / [12:41] <ZeroOne> https://dl.dropboxusercontent.com/u/15144168/stack.png here have another screenshot -// - I get this too - -#define uiParentClass L"uiParentClass" - -HWND initialParent; - -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 parent coordinates - 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()"); -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -// this X value is really only for buttons but I don't see a better one :/ -#define winXPadding 4 -#define winYPadding 4 - -static void resize(uiControl *control, HWND parent, RECT r, RECT margin) -{ - uiSizing d; - uiSizingSys sys; - HDC dc; - HFONT prevfont; - TEXTMETRICW tm; - SIZE size; - - size.cx = 0; - size.cy = 0; - ZeroMemory(&tm, sizeof (TEXTMETRICW)); - dc = GetDC(parent); - if (dc == NULL) - logLastError("error getting DC in resize()"); - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - logLastError("error loading control font into device context in resize()"); - if (GetTextMetricsW(dc, &tm) == 0) - logLastError("error getting text metrics in resize()"); - if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) - logLastError("error getting text extent point in resize()"); - sys.baseX = (int) ((size.cx / 26 + 1) / 2); - sys.baseY = (int) tm.tmHeight; - sys.internalLeading = tm.tmInternalLeading; - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError("error restoring previous font into device context in resize()"); - if (ReleaseDC(parent, dc) == 0) - logLastError("error releasing DC in resize()"); - r.left += uiDlgUnitsToX(margin.left, sys.baseX); - r.top += uiDlgUnitsToY(margin.top, sys.baseY); - r.right -= uiDlgUnitsToX(margin.right, sys.baseX); - r.bottom -= uiDlgUnitsToY(margin.bottom, sys.baseY); - d.xPadding = uiDlgUnitsToX(winXPadding, sys.baseX); - d.yPadding = uiDlgUnitsToY(winYPadding, sys.baseY); - d.sys = &sys; - uiControlResize(control, r.left, r.top, r.right - r.left, r.bottom - r.top, &d); -} - -struct parent { - HWND hwnd; - uiControl *child; - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; -}; - -static LRESULT CALLBACK parentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - uiParent *p; - struct parent *pp; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - HWND control; - NMHDR *nm = (NMHDR *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - RECT r, margin; - - // these must always be executed, even on the initial parent - // why? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx - switch (uMsg) { - case WM_COMMAND: - // bounce back to the control in question - // except if to the initial parent, in which case act as if the message was ignored - control = (HWND) lParam; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgCOMMAND, wParam, lParam); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - case WM_NOTIFY: - // same as WM_COMMAND - control = nm->hwndFrom; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgNOTIFY, wParam, lParam); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: -/*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 DefWindowProcW(hwnd, uMsg, wParam, lParam); -*/ if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - logLastError("error setting transparent background mode to controls in parentWndProc()"); - paintControlBackground((HWND) lParam, (HDC) wParam); - return (LRESULT) hollowBrush; - } - - // these are only executed on actual parents - p = (uiParent *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (p == NULL) { - if (uMsg == WM_NCCREATE) { - p = (uiParent *) (cs->lpCreateParams); - // this will be NULL for the initial parent; that's what we want - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) p); - // fall through to DefWindowProcW() - } - // this is the return the initial parent will always use - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - pp = (struct parent *) (p->Internal); - switch (uMsg) { - case WM_NCDESTROY: - // no need to explicitly destroy children; they're already gone by this point (and so are their data structures; they clean up after themselves) - uiFree(p->Internal); - uiFree(p); - break; // fall through to DefWindowPocW() - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // fall through - case msgUpdateChild: - if (pp->child == NULL) - break; - if (GetClientRect(pp->hwnd, &r) == 0) - logLastError("error getting client rect for resize in parentWndProc()"); - margin.left = pp->marginLeft; - margin.top = pp->marginTop; - margin.right = pp->marginRight; - margin.bottom = pp->marginBottom; - resize(pp->child, pp->hwnd, r, margin); - return 0; - } - - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -const char *initParent(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = uiParentClass; - wc.lpfnWndProc = parentWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - if (RegisterClassW(&wc) == 0) - return "registering parent window class"; - - initialParent = CreateWindowExW(0, - uiParentClass, L"", - WS_OVERLAPPEDWINDOW, - 0, 0, - 100, 100, - NULL, NULL, hInstance, NULL); - if (initialParent == NULL) - return "creating initial parent window"; - - // just to be safe, disable the initial parent so it can't be interacted with accidentally - // if this causes issues for our controls, we can remove it - EnableWindow(initialParent, FALSE); - return NULL; -} - -static uintptr_t parentHandle(uiParent *p) -{ - struct parent *pp = (struct parent *) (p->Internal); - - return (uintptr_t) (pp->hwnd); -} - -static void parentSetChild(uiParent *p, uiControl *child) -{ - struct parent *pp = (struct parent *) (p->Internal); - - pp->child = child; - if (pp->child != NULL) - uiControlSetParent(child, p); -} - -static void parentSetMargins(uiParent *p, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) -{ - struct parent *pp = (struct parent *) (p->Internal); - - pp->marginLeft = left; - pp->marginTop = top; - pp->marginRight = right; - pp->marginBottom = bottom; -} - -static void parentUpdate(uiParent *p) -{ - struct parent *pp = (struct parent *) (p->Internal); - - SendMessageW(pp->hwnd, msgUpdateChild, 0, 0); -} - -uiParent *uiNewParent(uintptr_t osParent) -{ - uiParent *p; - struct parent *pp; - - p = uiNew(uiParent); - p->Internal = uiNew(struct parent); // set now in case the parent class window procedure uses it - pp = (struct parent *) (p->Internal); - pp->hwnd = CreateWindowExW(0, - uiParentClass, L"", - WS_CHILD | WS_VISIBLE, - 0, 0, - 0, 0, - (HWND) osParent, NULL, hInstance, p); - if (pp->hwnd == NULL) - logLastError("error creating uiParent window in uiNewParent()"); - p->Handle = parentHandle; - p->SetChild = parentSetChild; - p->SetMargins = parentSetMargins; - p->Update = parentUpdate; - return p; -} diff --git a/new/windows/tab.c b/new/windows/tab.c deleted file mode 100644 index d2cbd62..0000000 --- a/new/windows/tab.c +++ /dev/null @@ -1,190 +0,0 @@ -// 12 april 2015 -#include "uipriv_windows.h" - -// TODO -// - tab change notifications aren't being sent on wine (anymore...? TODO) -// - tell wine developers that tab controls do respond to parent changes on real windows (at least comctl6 tab controls do) - -struct tab { - uiTab t; - uiParent **pages; - uintmax_t len; - uintmax_t cap; -}; - -static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) -{ - return FALSE; -} - -// we have to handle hiding and showing of tab pages ourselves -static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) -{ - struct tab *t = (struct tab *) c; - LRESULT n; - - switch (nm->code) { - case TCN_SELCHANGING: - n = SendMessageW(uiControlHWND(c), TCM_GETCURSEL, 0, 0); - if (n != (LRESULT) (-1)) // if we're changing to a real tab - ShowWindow(uiParentHWND(t->pages[n]), SW_HIDE); - *lResult = FALSE; // and allow the change - return TRUE; - case TCN_SELCHANGE: - n = SendMessageW(uiControlHWND(c), TCM_GETCURSEL, 0, 0); - if (n != (LRESULT) (-1)) { // if we're changing to a real tab - ShowWindow(uiParentHWND(t->pages[n]), SW_SHOW); - // because we only resize the current child on resize, we'll need to trigger an update here - // don't call uiParentUpdate(); doing that won't size the content area (so we'll still have a 0x0 content area, for instance) - SendMessageW(uiControlHWND(c), msgUpdateChild, 0, 0); - } - *lResult = 0; - return TRUE; - } - return FALSE; -} - -static void onWM_DESTROY(uiControl *c) -{ - struct tab *t = (struct tab *) c; - - // no need to worry about freeing the pages themselves; they'll destroy themselves after we return - uiFree(t->pages); - uiFree(t); -} - -static void preferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - // TODO -} - -// common code for resizes -static void resizeTab(uiControl *c, LONG width, LONG height) -{ - struct tab *t = (struct tab *) c; - HWND hwnd; - LRESULT n; - RECT r; - - hwnd = uiControlHWND(c); - - n = SendMessageW(hwnd, TCM_GETCURSEL, 0, 0); - if (n == (LRESULT) (-1)) // no child selected; do nothing - return; - - // make a rect at (0, 0) of the given window size - // this should give us the correct client coordinates - r.left = 0; - r.top = 0; - r.right = width; - r.bottom = height; - // convert to the display rectangle - SendMessageW(hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM) (&r)); - - if (MoveWindow(uiParentHWND(t->pages[n]), r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE) == 0) - logLastError("error resizing current tab page in resizeTab()"); -} - -// and finally, because we have to resize parents, we have to handle resizes and updates -static LRESULT CALLBACK tabSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - uiControl *c = (uiControl *) dwRefData; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - LRESULT lResult; - RECT r; - - switch (uMsg) { - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // first, let the tab control handle it - lResult = (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); - // we have the window rect width as part of the WINDOWPOS; resize - resizeTab(c, wp->cx, wp->cy); - return lResult; - case msgUpdateChild: - if (GetWindowRect(uiControlHWND(c), &r) == 0) - logLastError("error getting Tab window rect for synthesized resize message in tabSubProc()"); - // these are in screen coordinates, which match what WM_WINDOWPOSCHANGED gave us (thanks TODOTODOTODOTODOTODOTODOTODO) - resizeTab(c, r.right - r.left, r.bottom - r.top); - return 0; - case WM_NCDESTROY: - if ((*fv_RemoveWindowSubclass)(hwnd, tabSubProc, uIdSubclass) == FALSE) - logLastError("error removing Tab resize handling subclass in tabSubProc()"); - break; - } - return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); -} - -#define tabCapGrow 32 - -void addPage(uiTab *tt, const char *name, uiControl *child) -{ - struct tab *t = (struct tab *) tt; - HWND hwnd; - TCITEMW item; - LRESULT n; - uiParent *parent; - WCHAR *wname; - - if (t->len >= t->cap) { - t->cap += tabCapGrow; - t->pages = (uiParent **) uiRealloc(t->pages, t->cap * sizeof (uiParent *), "uiParent *[]"); - } - - hwnd = uiControlHWND(uiControl(t)); - n = SendMessageW(hwnd, TCM_GETITEMCOUNT, 0, 0); - - parent = uiNewParent((uintptr_t) hwnd); - uiParentSetChild(parent, child); - uiParentUpdate(parent); - if (n != 0) // if this isn't the first page, we have to hide the other controls - ShowWindow(uiParentHWND(parent), SW_HIDE); - t->pages[t->len] = parent; - t->len++; - - ZeroMemory(&item, sizeof (TCITEMW)); - item.mask = TCIF_TEXT; - wname = toUTF16(name); - item.pszText = wname; - // MSDN's example code uses the first invalid index directly for this - if (SendMessageW(hwnd, TCM_INSERTITEM, (WPARAM) n, (LPARAM) (&item)) == (LRESULT) -1) - logLastError("error adding tab to Tab in uiTabAddPage()"); - uiFree(wname); - - // if this is the first tab, Windows will automatically show it /without/ sending a TCN_SELCHANGE notification - // (TODO verify that) - // so we need to manually resize the tab ourselves - // don't use uiUpdateParent() for the same reason as in the TCN_SELCHANGE handler - SendMessageW(hwnd, msgUpdateChild, 0, 0); -} - -uiTab *uiNewTab(void) -{ - struct tab *t; - uiWindowsNewControlParams p; - HWND hwnd; - - t = uiNew(struct tab); - - p.dwExStyle = 0; // don't set WS_EX_CONTROLPARENT yet; we do that dynamically in the message loop (see main_windows.c) - p.lpClassName = WC_TABCONTROLW; - p.lpWindowName = L""; - p.dwStyle = TCS_TOOLTIPS | WS_TABSTOP; - p.hInstance = hInstance; - p.useStandardControlFont = TRUE; - p.onWM_COMMAND = onWM_COMMAND; - p.onWM_NOTIFY = onWM_NOTIFY; - p.onWM_DESTROY = onWM_DESTROY; - uiWindowsNewControl(uiControl(t), &p); - - hwnd = uiControlHWND(uiControl(t)); - if ((*fv_SetWindowSubclass)(hwnd, tabSubProc, 0, (DWORD_PTR) t) == FALSE) - logLastError("error subclassing Tab to give it its own resize handler in uiNewTab()"); - - uiControl(t)->PreferredSize = preferredSize; - - uiTab(t)->AddPage = addPage; - - return uiTab(t); -} diff --git a/new/windows/text.c b/new/windows/text.c deleted file mode 100644 index 8d6d0b0..0000000 --- a/new/windows/text.c +++ /dev/null @@ -1,55 +0,0 @@ -// 9 april 2015 -#include "uipriv_windows.h" - -// see http://stackoverflow.com/a/29556509/3408572 - -#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz) - -WCHAR *toUTF16(const char *str) -{ - WCHAR *wstr; - int n; - - n = MBTWC(str, NULL, 0); - if (n == 0) - logLastError("error figuring out number of characters to convert to in toUTF16()"); - wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); - if (MBTWC(str, wstr, n) != n) - logLastError("error converting from UTF-8 to UTF-16 in toUTF16()"); - return wstr; -} - -#define WCTMB(wstr, str, bufsiz) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, bufsiz, NULL, NULL) - -char *toUTF8(const WCHAR *wstr) -{ - char *str; - int n; - - n = WCTMB(wstr, NULL, 0); - if (n == 0) - logLastError("error figuring out number of characters to convert to in toUTF8()"); - str = (char *) uiAlloc(n * sizeof (char), "char[]"); - if (WCTMB(wstr, str, n) != n) - logLastError("error converting from UTF-16 to UTF-8 in toUTFF8()"); - return str; -} - -WCHAR *windowText(HWND hwnd) -{ - LRESULT n; - WCHAR *text; - - n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - // WM_GETTEXTLENGTH does not include the null terminator - text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - // note the comparison: the size includes the null terminator, but the return does not - if (GetWindowTextW(hwnd, text, n + 1) != n) - logLastError("error getting window text in windowText()"); - return text; -} - -void uiFreeText(char *text) -{ - uiFree(text); -} diff --git a/new/windows/uipriv_windows.h b/new/windows/uipriv_windows.h deleted file mode 100644 index 4ba0f5a..0000000 --- a/new/windows/uipriv_windows.h +++ /dev/null @@ -1,69 +0,0 @@ -// 6 january 2015 -#define UNICODE -#define _UNICODE -#define STRICT -#define STRICT_TYPED_ITEMIDS -#define CINTERFACE -#define COBJMACROS -// see https://github.com/golang/go/issues/9916#issuecomment-74812211 -#define INITGUID -// get Windows version right; right now Windows XP -#define WINVER 0x0501 -#define _WIN32_WINNT 0x0501 -#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */ -#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */ -#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */ -#include <windows.h> -#include <commctrl.h> -#include <stdint.h> -#include <uxtheme.h> -#include <string.h> -#include <wchar.h> -#include <windowsx.h> -#include <vsstyle.h> -#include <vssym32.h> -#include <stdarg.h> -#include <oleacc.h> -#include <stdio.h> -#include "../uipriv.h" -#include "../ui_windows.h" - -// ui internal window messages -enum { - // redirected WM_COMMAND and WM_NOTIFY - msgCOMMAND = WM_APP + 0x40, // start offset just to be safe - msgNOTIFY, - msgUpdateChild, // fake because Windows seems to SWP_NOSIZE MoveWindow()s and SetWindowPos()s that don't change the window size (even if SWP_NOSIZE isn't specified) -}; - -// debug_windows.c -extern HRESULT logLastError(const char *); -extern HRESULT logHRESULT(const char *, HRESULT); -extern HRESULT logMemoryExhausted(const char *); - -// init_windows.c -extern HINSTANCE hInstance; -extern int nCmdShow; -extern HFONT hMessageFont; -extern HBRUSH hollowBrush; - -// util_windows.c -extern int windowClassOf(HWND, ...); - -// text_windows.c -extern WCHAR *toUTF16(const char *); -extern char *toUTF8(const WCHAR *); -extern WCHAR *windowText(HWND); - -// comctl32_windows.c -extern BOOL (*WINAPI fv_SetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR); -extern BOOL (*WINAPI fv_RemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); -extern LRESULT (*WINAPI fv_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); -extern const char *initCommonControls(void); - -// window_windows.c -extern ATOM registerWindowClass(HICON, HCURSOR); - -// parent_windows.c -extern HWND initialParent; -extern const char *initParent(HICON, HCURSOR); diff --git a/new/windows/util.c b/new/windows/util.c deleted file mode 100644 index 93b32d8..0000000 --- a/new/windows/util.c +++ /dev/null @@ -1,73 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -intmax_t uiWindowsWindowTextWidth(HWND hwnd) -{ - LRESULT len; - WCHAR *text; - HDC dc; - HFONT prevfont; - SIZE size; - - size.cx = 0; - size.cy = 0; - - // first we need the window text - len = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); - if (len == 0) // no text; nothing to do - return 0; - text = (WCHAR *) uiAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]"); - // note the comparison: the size includes the null terminator, but the return does not - if (GetWindowText(hwnd, text, len + 1) != len) - logLastError("error getting window text in uiWindowsWindowTextWidth()"); - - // now we can do the calculations - dc = GetDC(hwnd); - if (dc == NULL) - logLastError("error getting DC in uiWindowsWindowTextWidth()"); - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - logLastError("error loading control font into device context in uiWindowsWindowTextWidth()"); - if (GetTextExtentPoint32W(dc, text, len, &size) == 0) - logLastError("error getting text extent point in uiWindowsWindowTextWidth()"); - if (SelectObject(dc, prevfont) != hMessageFont) - logLastError("error restoring previous font into device context in uiWindowsWindowTextWidth()"); - if (ReleaseDC(hwnd, dc) == 0) - logLastError("error releasing DC in uiWindowsWindowTextWidth()"); - uiFree(text); - - 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; -} diff --git a/new/windows/window.c b/new/windows/window.c deleted file mode 100644 index e9360eb..0000000 --- a/new/windows/window.c +++ /dev/null @@ -1,216 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -struct window { - uiWindow w; - HWND hwnd; - uiParent *content; - BOOL shownOnce; - int (*onClosing)(uiWindow *, void *); - void *onClosingData; - int margined; -}; - -#define uiWindowClass L"uiWindowClass" - -static LRESULT CALLBACK uiWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - struct window *w; - CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; - WINDOWPOS *wp = (WINDOWPOS *) lParam; - RECT r; - HWND contenthwnd; - - w = (struct window *) GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (w == NULL) { - if (uMsg == WM_CREATE) - SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) (cs->lpCreateParams)); - // fall through to DefWindowProc() anyway - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - switch (uMsg) { - case WM_WINDOWPOSCHANGED: - if ((wp->flags & SWP_NOSIZE) != 0) - break; - // fall through - case msgUpdateChild: - if (GetClientRect(w->hwnd, &r) == 0) - logLastError("error getting window client rect for resize in uiWindowWndProc()"); - contenthwnd = uiParentHWND(w->content); - if (MoveWindow(contenthwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE) == 0) - logLastError("error resizing window content parent in uiWindowWndProc()"); - return 0; - case WM_CLOSE: - if (!(*(w->onClosing))(uiWindow(w), w->onClosingData)) - return 0; - break; // fall through to DefWindowProcW() - case WM_DESTROY: - // no need to free the child ourselves; it'll destroy itself after we leave this handler - uiFree(w); - break; // fall through to DefWindowProcW() - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - -ATOM registerWindowClass(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = uiWindowClass; - wc.lpfnWndProc = uiWindowWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - return RegisterClassW(&wc); -} - -#define exstyle 0 -#define style WS_OVERLAPPEDWINDOW - -static int defaultOnClosing(uiWindow *w, void *data) -{ - return 1; -} - -static void windowDestroy(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - DestroyWindow(w->hwnd); -} - -static uintptr_t windowHandle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return (uintptr_t) (w->hwnd); -} - -static char *windowTitle(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - WCHAR *wtext; - char *text; - - wtext = windowText(w->hwnd); - text = toUTF8(wtext); - uiFree(wtext); - return text; -} - -static void windowSetTitle(uiWindow *ww, const char *text) -{ - struct window *w = (struct window *) ww; - WCHAR *wtext; - - wtext = toUTF16(text); - if (SetWindowTextW(w->hwnd, wtext) == 0) - logLastError("error setting window title in uiWindowSetTitle()"); - uiFree(wtext); -} - -static void windowShow(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - if (w->shownOnce) { - ShowWindow(w->hwnd, SW_SHOW); - return; - } - w->shownOnce = TRUE; - ShowWindow(w->hwnd, nCmdShow); - if (UpdateWindow(w->hwnd) == 0) - logLastError("error calling UpdateWindow() after showing uiWindow for the first time"); -} - -static void windowHide(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - ShowWindow(w->hwnd, SW_HIDE); -} - -static void windowOnClosing(uiWindow *ww, int (*f)(uiWindow *, void *), void *data) -{ - struct window *w = (struct window *) ww; - - w->onClosing = f; - w->onClosingData = data; -} - -static void windowSetChild(uiWindow *ww, uiControl *c) -{ - struct window *w = (struct window *) ww; - - uiParentSetChild(w->content, c); - // don't call uiParentUpdate(); instead, synthesize a resize - // otherwise, we'll have a 0x0 content area at first - SendMessageW(w->hwnd, msgUpdateChild, 0, 0); -} - -static int windowMargined(uiWindow *ww) -{ - struct window *w = (struct window *) ww; - - return w->margined; -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define windowMargin 7 - -static void windowSetMargined(uiWindow *ww, int margined) -{ - struct window *w = (struct window *) ww; - - w->margined = margined; - if (w->margined) - uiParentSetMargins(w->content, windowMargin, windowMargin, windowMargin, windowMargin); - else - uiParentSetMargins(w->content, 0, 0, 0, 0); - uiParentUpdate(w->content); -} - -uiWindow *uiNewWindow(const char *title, int width, int height) -{ - struct window *w; - RECT adjust; - WCHAR *wtitle; - - w = uiNew(struct window); - w->onClosing = defaultOnClosing; - - adjust.left = 0; - adjust.top = 0; - adjust.right = width; - adjust.bottom = height; - if (AdjustWindowRectEx(&adjust, style, FALSE, exstyle) == 0) - logLastError("error getting real window coordinates in uiWindow()"); - - wtitle = toUTF16(title); - w->hwnd = CreateWindowExW(exstyle, - uiWindowClass, wtitle, - style, - CW_USEDEFAULT, CW_USEDEFAULT, - adjust.right - adjust.left, adjust.bottom - adjust.top, - NULL, NULL, hInstance, w); - if (w->hwnd == NULL) - logLastError("error creating window in uiWindow()"); - uiFree(wtitle); - - w->content = uiNewParent((uintptr_t) (w->hwnd)); - - uiWindow(w)->Destroy = windowDestroy; - uiWindow(w)->Handle = windowHandle; - uiWindow(w)->Title = windowTitle; - uiWindow(w)->SetTitle = windowSetTitle; - uiWindow(w)->Show = windowShow; - uiWindow(w)->Hide = windowHide; - uiWindow(w)->OnClosing = windowOnClosing; - uiWindow(w)->SetChild = windowSetChild; - uiWindow(w)->Margined = windowMargined; - uiWindow(w)->SetMargined = windowSetMargined; - - return uiWindow(w); -} |
