(libui) Update comments

This commit is contained in:
twinaphex 2017-07-03 09:33:29 +02:00
parent 1521a8dd38
commit 760fee18dd
6 changed files with 231 additions and 213 deletions

View File

@ -1,26 +1,26 @@
// 26 april 2015 /* 26 april 2015 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
// This contains code used by all uiControls that contain other controls. /* This contains code used by all uiControls that contain other controls.
// It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. * It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. */
static HBRUSH parentBrush = NULL; static HBRUSH parentBrush = NULL;
static HWND parentWithBackground(HWND hwnd) static HWND parentWithBackground(HWND hwnd)
{ {
HWND parent; int cls;
int cls; HWND parent = hwnd;
parent = hwnd; for (;;)
for (;;) { {
parent = parentOf(parent); parent = parentOf(parent);
// skip groupboxes; they're (supposed to be) transparent /* skip groupboxes; they're (supposed to be) transparent
// skip uiContainers; they don't draw anything * skip uiContainers; they don't draw anything */
cls = windowClassOf(parent, L"button", containerClass, NULL); cls = windowClassOf(parent, L"button", containerClass, NULL);
if (cls != 0 && cls != 1) if (cls != 0 && cls != 1)
break; break;
} }
return parent; return parent;
} }
struct parentDraw { struct parentDraw {
@ -49,7 +49,7 @@ static HRESULT parentDraw(HDC dc, HWND parent, struct parentDraw *pd)
static void endParentDraw(struct parentDraw *pd) static void endParentDraw(struct parentDraw *pd)
{ {
// continue in case of any error /* continue in case of any error */
if (pd->prevbitmap != NULL) if (pd->prevbitmap != NULL)
if (((HBITMAP) SelectObject(pd->cdc, pd->prevbitmap)) != pd->bitmap) if (((HBITMAP) SelectObject(pd->cdc, pd->prevbitmap)) != pd->bitmap)
logLastError(L"error selecting previous bitmap back into compatible DC"); logLastError(L"error selecting previous bitmap back into compatible DC");
@ -61,7 +61,7 @@ static void endParentDraw(struct parentDraw *pd)
logLastError(L"error deleting compatible DC"); logLastError(L"error deleting compatible DC");
} }
// see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP /* see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP */
static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc)
{ {
HWND parent; HWND parent;
@ -83,10 +83,11 @@ static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc)
} }
endParentDraw(&pd); endParentDraw(&pd);
// now figure out where the control is relative to the parent so we can align the brush properly /* now figure out where the control is relative to the parent
// if anything fails, give up and return the brush as-is * so we can align the brush properly
* if anything fails, give up and return the brush as-is */
uiWindowsEnsureGetWindowRect(hwnd, &hwndScreenRect); uiWindowsEnsureGetWindowRect(hwnd, &hwndScreenRect);
// this will be in screen coordinates; convert to parent coordinates /* this will be in screen coordinates; convert to parent coordinates */
mapWindowRect(NULL, parent, &hwndScreenRect); mapWindowRect(NULL, parent, &hwndScreenRect);
if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0) if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0)
logLastError(L"error setting brush origin"); logLastError(L"error setting brush origin");
@ -96,19 +97,18 @@ static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc)
void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect) void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect)
{ {
HWND parent;
RECT paintRectParent; RECT paintRectParent;
struct parentDraw pd; struct parentDraw pd;
HRESULT hr; HWND parent = parentWithBackground(hwnd);
HRESULT hr = parentDraw(dc, parent, &pd);
parent = parentWithBackground(hwnd); if (hr != S_OK) /* we couldn't get it; draw nothing */
hr = parentDraw(dc, parent, &pd);
if (hr != S_OK) // we couldn't get it; draw nothing
return; return;
paintRectParent = *paintRect; paintRectParent = *paintRect;
mapWindowRect(hwnd, parent, &paintRectParent); mapWindowRect(hwnd, parent, &paintRectParent);
if (BitBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, if (BitBlt(dc, paintRect->left, paintRect->top,
paintRect->right - paintRect->left, paintRect->bottom - paintRect->top,
pd.cdc, paintRectParent.left, paintRectParent.top, pd.cdc, paintRectParent.left, paintRectParent.top,
SRCCOPY) == 0) SRCCOPY) == 0)
logLastError(L"error drawing parent background over uiContainer"); logLastError(L"error drawing parent background over uiContainer");
@ -116,29 +116,31 @@ void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect)
endParentDraw(&pd); endParentDraw(&pd);
} }
// TODO make this public if we want custom containers /* TODO make this public if we want custom containers
// why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx * why have this to begin with? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx */
BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult) BOOL handleParentMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
{ {
switch (uMsg) { switch (uMsg)
case WM_COMMAND: {
return runWM_COMMAND(wParam, lParam, lResult); case WM_COMMAND:
case WM_NOTIFY: return runWM_COMMAND(wParam, lParam, lResult);
return runWM_NOTIFY(wParam, lParam, lResult); case WM_NOTIFY:
case WM_HSCROLL: return runWM_NOTIFY(wParam, lParam, lResult);
return runWM_HSCROLL(wParam, lParam, lResult); case WM_HSCROLL:
case WM_CTLCOLORSTATIC: return runWM_HSCROLL(wParam, lParam, lResult);
case WM_CTLCOLORBTN: case WM_CTLCOLORSTATIC:
if (parentBrush != NULL) case WM_CTLCOLORBTN:
if (DeleteObject(parentBrush) == 0) if (parentBrush != NULL)
logLastError(L"error deleting old background brush()"); // but continue anyway; we will leak a brush but whatever if (DeleteObject(parentBrush) == 0)
if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) logLastError(L"error deleting old background brush()"); /* but continue anyway; we will leak a brush but whatever */
logLastError(L"error setting transparent background mode to controls"); // but continue anyway; text will be wrong if (SetBkMode((HDC) wParam, TRANSPARENT) == 0)
parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam); logLastError(L"error setting transparent background mode to controls"); /* but continue anyway; text will be wrong */
if (parentBrush == NULL) // failed; just do default behavior parentBrush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam);
return FALSE; if (parentBrush == NULL) /* failed; just do default behavior */
*lResult = (LRESULT) parentBrush; return FALSE;
return TRUE; *lResult = (LRESULT) parentBrush;
} return TRUE;
return FALSE; }
return FALSE;
} }

View File

@ -1,18 +1,18 @@
// 16 may 2015 /* 16 may 2015 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
// You don't add controls directly to a tab control on Windows; instead you make them siblings and swap between them on a TCN_SELCHANGING/TCN_SELCHANGE notification pair. /* You don't add controls directly to a tab control on Windows; instead you make them siblings and swap between them on a TCN_SELCHANGING/TCN_SELCHANGE notification pair.
// In addition, you use dialogs because they can be textured properly; other controls cannot. (Things will look wrong if the tab background in the current theme is fancy if you just use the tab background by itself; see http://stackoverflow.com/questions/30087540/why-are-my-programss-tab-controls-rendering-their-background-in-a-blocky-way-b.) * In addition, you use dialogs because they can be textured properly; other controls cannot. (Things will look wrong if the tab background in the current theme is fancy if you just use the tab background by itself; see http://stackoverflow.com/questions/30087540/why-are-my-programss-tab-controls-rendering-their-background-in-a-blocky-way-b.) */
struct uiTab { struct uiTab {
uiWindowsControl c; uiWindowsControl c;
HWND hwnd; // of the outer container HWND hwnd; /* of the outer container */
HWND tabHWND; // of the tab control itself HWND tabHWND; /* of the tab control itself */
std::vector<struct tabPage *> *pages; std::vector<struct tabPage *> *pages;
HWND parent; HWND parent;
}; };
// utility functions /* utility functions */
static LRESULT curpage(uiTab *t) static LRESULT curpage(uiTab *t)
{ {
@ -26,11 +26,14 @@ static struct tabPage *tabPage(uiTab *t, int i)
static void tabPageRect(uiTab *t, RECT *r) static void tabPageRect(uiTab *t, RECT *r)
{ {
// this rect needs to be in parent window coordinates, but TCM_ADJUSTRECT wants a window rect, which is screen coordinates /* this rect needs to be in parent window coordinates, but TCM_ADJUSTRECT
// because we have each page as a sibling of the tab, use the tab's own rect as the input rect * wants a window rect, which is screen coordinates
* because we have each page as a sibling of the tab, use the tab's
* own rect as the input rect */
uiWindowsEnsureGetWindowRect(t->tabHWND, r); uiWindowsEnsureGetWindowRect(t->tabHWND, r);
SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) FALSE, (LPARAM) r); SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) FALSE, (LPARAM) r);
// and get it in terms of the container instead of the screen
/* and get it in terms of the container instead of the screen */
mapWindowRect(NULL, t->hwnd, r); mapWindowRect(NULL, t->hwnd, r);
} }
@ -39,11 +42,11 @@ static void tabRelayout(uiTab *t)
struct tabPage *page; struct tabPage *page;
RECT r; RECT r;
// first move the tab control itself /* first move the tab control itself */
uiWindowsEnsureGetClientRect(t->hwnd, &r); uiWindowsEnsureGetClientRect(t->hwnd, &r);
uiWindowsEnsureMoveWindowDuringResize(t->tabHWND, r.left, r.top, r.right - r.left, r.bottom - r.top); uiWindowsEnsureMoveWindowDuringResize(t->tabHWND, r.left, r.top, r.right - r.left, r.bottom - r.top);
// then the current page /* then the current page */
if (t->pages->size() == 0) if (t->pages->size() == 0)
return; return;
page = tabPage(t, curpage(t)); page = tabPage(t, curpage(t));
@ -53,21 +56,22 @@ static void tabRelayout(uiTab *t)
static void showHidePage(uiTab *t, LRESULT which, int hide) static void showHidePage(uiTab *t, LRESULT which, int hide)
{ {
struct tabPage *page; struct tabPage *page = NULL;
if (which == (LRESULT) (-1)) if (which == (LRESULT) (-1))
return; return;
page = tabPage(t, which); page = tabPage(t, which);
if (hide) if (hide)
ShowWindow(page->hwnd, SW_HIDE); ShowWindow(page->hwnd, SW_HIDE);
else { else
ShowWindow(page->hwnd, SW_SHOW); {
// we only resize the current page, so we have to resize it; before we can do that, we need to make sure we are of the right size ShowWindow(page->hwnd, SW_SHOW);
uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); /* we only resize the current page, so we have to resize it; before we can do that, we need to make sure we are of the right size */
} uiWindowsControlMinimumSizeChanged(uiWindowsControl(t));
}
} }
// control implementation /* control implementation */
static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult) static BOOL onWM_NOTIFY(uiControl *c, HWND hwnd, NMHDR *nm, LRESULT *lResult)
{ {
@ -129,22 +133,23 @@ uiWindowsControlDefaultSetParentHWND(uiTab)
static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height) static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height)
{ {
uiTab *t = uiTab(c);
int pagewid, pageht;
struct tabPage *page;
RECT r; RECT r;
struct tabPage *page = NULL;
uiTab *t = uiTab(c);
// only consider the current page /* only consider the current page */
pagewid = 0; int pagewid = 0;
pageht = 0; int pageht = 0;
if (t->pages->size() != 0) {
if (t->pages->size() != 0)
{
page = tabPage(t, curpage(t)); page = tabPage(t, curpage(t));
tabPageMinimumSize(page, &pagewid, &pageht); tabPageMinimumSize(page, &pagewid, &pageht);
} }
r.left = 0; r.left = 0;
r.top = 0; r.top = 0;
r.right = pagewid; r.right = pagewid;
r.bottom = pageht; r.bottom = pageht;
// this also includes the tabs themselves // this also includes the tabs themselves
SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) TRUE, (LPARAM) (&r)); SendMessageW(t->tabHWND, TCM_ADJUSTRECT, (WPARAM) TRUE, (LPARAM) (&r));
@ -154,13 +159,14 @@ static void uiTabMinimumSize(uiWindowsControl *c, int *width, int *height)
static void uiTabMinimumSizeChanged(uiWindowsControl *c) static void uiTabMinimumSizeChanged(uiWindowsControl *c)
{ {
uiTab *t = uiTab(c); uiTab *t = uiTab(c);
if (uiWindowsControlTooSmall(uiWindowsControl(t))) { if (uiWindowsControlTooSmall(uiWindowsControl(t)))
uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(t)); {
return; uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(t));
} return;
tabRelayout(t); }
tabRelayout(t);
} }
uiWindowsControlDefaultLayoutRect(uiTab) uiWindowsControlDefaultLayoutRect(uiTab)
@ -168,16 +174,16 @@ uiWindowsControlDefaultAssignControlIDZOrder(uiTab)
static void uiTabChildVisibilityChanged(uiWindowsControl *c) static void uiTabChildVisibilityChanged(uiWindowsControl *c)
{ {
// TODO eliminate the redundancy /* TODO eliminate the redundancy */
uiWindowsControlMinimumSizeChanged(c); uiWindowsControlMinimumSizeChanged(c);
} }
static void tabArrangePages(uiTab *t) static void tabArrangePages(uiTab *t)
{ {
LONG_PTR controlID = 100; LONG_PTR controlID = 100;
HWND insertAfter = NULL; HWND insertAfter = NULL;
// TODO is this first or last? /* TODO is this first or last? */
uiWindowsEnsureAssignControlIDZOrder(t->tabHWND, &controlID, &insertAfter); uiWindowsEnsureAssignControlIDZOrder(t->tabHWND, &controlID, &insertAfter);
for (struct tabPage *&page : *(t->pages)) for (struct tabPage *&page : *(t->pages))
uiWindowsEnsureAssignControlIDZOrder(page->hwnd, &controlID, &insertAfter); uiWindowsEnsureAssignControlIDZOrder(page->hwnd, &controlID, &insertAfter);
@ -191,12 +197,11 @@ void uiTabAppend(uiTab *t, const char *name, uiControl *child)
void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child) void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child)
{ {
struct tabPage *page; struct tabPage *page;
LRESULT hide, show; LRESULT show;
TCITEMW item; TCITEMW item;
WCHAR *wname; WCHAR *wname;
/* see below */
// see below LRESULT hide = curpage(t);
hide = curpage(t);
if (child != NULL) if (child != NULL)
uiControlSetParent(child, uiControl(t)); uiControlSetParent(child, uiControl(t));
@ -214,9 +219,12 @@ void uiTabInsertAt(uiTab *t, const char *name, int n, uiControl *child)
logLastError(L"error adding tab to uiTab"); logLastError(L"error adding tab to uiTab");
uiFree(wname); uiFree(wname);
// we need to do this because adding the first tab doesn't send a TCN_SELCHANGE; it just shows the page /* we need to do this because adding the first tab
* doesn't send a TCN_SELCHANGE; it just shows the page */
show = curpage(t); show = curpage(t);
if (show != hide) {
if (show != hide)
{
showHidePage(t, hide, 1); showHidePage(t, hide, 1);
showHidePage(t, show, 0); showHidePage(t, show, 0);
} }
@ -226,12 +234,12 @@ void uiTabDelete(uiTab *t, int n)
{ {
struct tabPage *page; struct tabPage *page;
// first delete the tab from the tab control /* first delete the tab from the tab control
// if this is the current tab, no tab will be selected, which is good * if this is the current tab, no tab will be selected, which is good */
if (SendMessageW(t->tabHWND, TCM_DELETEITEM, (WPARAM) n, 0) == FALSE) if (SendMessageW(t->tabHWND, TCM_DELETEITEM, (WPARAM) n, 0) == FALSE)
logLastError(L"error deleting uiTab tab"); logLastError(L"error deleting uiTab tab");
// now delete the page itself /* now delete the page itself */
page = tabPage(t, n); page = tabPage(t, n);
if (page->child != NULL) if (page->child != NULL)
uiControlSetParent(page->child, NULL); uiControlSetParent(page->child, NULL);
@ -251,11 +259,13 @@ int uiTabMargined(uiTab *t, int n)
void uiTabSetMargined(uiTab *t, int n, int margined) void uiTabSetMargined(uiTab *t, int n, int margined)
{ {
struct tabPage *page; struct tabPage *page = tabPage(t, n);
page = tabPage(t, n);
page->margined = margined; page->margined = margined;
// even if the page doesn't have a child it might still have a new minimum size with margins; this is the easiest way to verify it
/* even if the page doesn't have a child it might still
* have a new minimum size with margins; this is the
* easiest way to verify it */
uiWindowsControlMinimumSizeChanged(uiWindowsControl(t)); uiWindowsControlMinimumSizeChanged(uiWindowsControl(t));
} }

View File

@ -1,36 +1,37 @@
// 9 april 2015 /* 9 april 2015 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len) WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len)
{ {
LRESULT n; WCHAR *text = NULL;
WCHAR *text; LRESULT n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0);
n = SendMessageW(hwnd, WM_GETTEXTLENGTH, 0, 0); if (len != NULL)
if (len != NULL) *len = n;
*len = n; /* WM_GETTEXTLENGTH does not include the null terminator */
// WM_GETTEXTLENGTH does not include the null terminator text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]");
text = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); /* note the comparison: the size includes the
// note the comparison: the size includes the null terminator, but the return does not * null terminator, but the return does not */
if (GetWindowTextW(hwnd, text, n + 1) != n) { if (GetWindowTextW(hwnd, text, n + 1) != n)
logLastError(L"error getting window text"); {
// on error, return an empty string to be safe logLastError(L"error getting window text");
*text = L'\0'; /* on error, return an empty string to be safe */
if (len != NULL) *text = L'\0';
*len = 0; if (len != NULL)
} *len = 0;
return text; }
return text;
} }
WCHAR *windowText(HWND hwnd) WCHAR *windowText(HWND hwnd)
{ {
return windowTextAndLen(hwnd, NULL); return windowTextAndLen(hwnd, NULL);
} }
void setWindowText(HWND hwnd, WCHAR *wtext) void setWindowText(HWND hwnd, WCHAR *wtext)
{ {
if (SetWindowTextW(hwnd, wtext) == 0) if (SetWindowTextW(hwnd, wtext) == 0)
logLastError(L"error setting window text"); logLastError(L"error setting window text");
} }
void uiFreeText(char *text) void uiFreeText(char *text)
@ -40,68 +41,65 @@ void uiFreeText(char *text)
int uiWindowsWindowTextWidth(HWND hwnd) int uiWindowsWindowTextWidth(HWND hwnd)
{ {
LRESULT len; LRESULT len;
WCHAR *text; HDC dc;
HDC dc; HFONT prevfont;
HFONT prevfont; SIZE size;
SIZE size; WCHAR *text = windowTextAndLen(hwnd, &len);
size.cx = 0; size.cx = 0;
size.cy = 0; size.cy = 0;
text = windowTextAndLen(hwnd, &len); if (len == 0) /* no text; nothing to do */
if (len == 0) // no text; nothing to do goto noTextOrError;
goto noTextOrError;
// now we can do the calculations /* now we can do the calculations */
dc = GetDC(hwnd); dc = GetDC(hwnd);
if (dc == NULL) { if (dc == NULL)
logLastError(L"error getting DC"); {
// on any error, assume no text logLastError(L"error getting DC");
goto noTextOrError; /* on any error, assume no text */
} goto noTextOrError;
prevfont = (HFONT) SelectObject(dc, hMessageFont); }
if (prevfont == NULL) { prevfont = (HFONT) SelectObject(dc, hMessageFont);
logLastError(L"error loading control font into device context"); if (prevfont == NULL)
ReleaseDC(hwnd, dc); {
goto noTextOrError; logLastError(L"error loading control font into device context");
} ReleaseDC(hwnd, dc);
if (GetTextExtentPoint32W(dc, text, len, &size) == 0) { goto noTextOrError;
logLastError(L"error getting text extent point"); }
// continue anyway, assuming size is 0 if (GetTextExtentPoint32W(dc, text, len, &size) == 0)
size.cx = 0; {
size.cy = 0; logLastError(L"error getting text extent point");
} /* continue anyway, assuming size is 0 */
// continue on errors; we got what we want size.cx = 0;
if (SelectObject(dc, prevfont) != hMessageFont) size.cy = 0;
logLastError(L"error restoring previous font into device context"); }
if (ReleaseDC(hwnd, dc) == 0) /* continue on errors; we got what we want */
logLastError(L"error releasing DC"); if (SelectObject(dc, prevfont) != hMessageFont)
logLastError(L"error restoring previous font into device context");
if (ReleaseDC(hwnd, dc) == 0)
logLastError(L"error releasing DC");
uiFree(text); uiFree(text);
return size.cx; return size.cx;
noTextOrError: noTextOrError:
uiFree(text); uiFree(text);
return 0; return 0;
} }
char *uiWindowsWindowText(HWND hwnd) char *uiWindowsWindowText(HWND hwnd)
{ {
WCHAR *wtext; WCHAR *wtext = windowText(hwnd);
char *text; char *text = toUTF8(wtext);
wtext = windowText(hwnd);
text = toUTF8(wtext);
uiFree(wtext); uiFree(wtext);
return text; return text;
} }
void uiWindowsSetWindowText(HWND hwnd, const char *text) void uiWindowsSetWindowText(HWND hwnd, const char *text)
{ {
WCHAR *wtext; WCHAR *wtext = toUTF16(text);
wtext = toUTF16(text);
setWindowText(hwnd, wtext); setWindowText(hwnd, wtext);
uiFree(wtext); uiFree(wtext);
} }

View File

@ -1,7 +1,7 @@
// 21 april 2016 /* 21 april 2016 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
// see http://stackoverflow.com/a/29556509/3408572 /* see http://stackoverflow.com/a/29556509/3408572 */
#define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz) #define MBTWC(str, wstr, bufsiz) MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, bufsiz)
@ -18,9 +18,10 @@ WCHAR *toUTF16(const char *str)
return emptyUTF16(); return emptyUTF16();
} }
wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); wstr = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]");
if (MBTWC(str, wstr, n) != n) { if (MBTWC(str, wstr, n) != n)
{
logLastError(L"error converting from UTF-8 to UTF-16"); logLastError(L"error converting from UTF-8 to UTF-16");
// and return an empty string /* and return an empty string */
*wstr = L'\0'; *wstr = L'\0';
} }
return wstr; return wstr;
@ -33,7 +34,7 @@ char *toUTF8(const WCHAR *wstr)
char *str; char *str;
int n; int n;
if (*wstr == L'\0') // empty string if (*wstr == L'\0') /* empty string */
return emptyUTF8(); return emptyUTF8();
n = WCTMB(wstr, NULL, 0); n = WCTMB(wstr, NULL, 0);
if (n == 0) { if (n == 0) {
@ -41,11 +42,12 @@ char *toUTF8(const WCHAR *wstr)
return emptyUTF8(); return emptyUTF8();
} }
str = (char *) uiAlloc(n * sizeof (char), "char[]"); str = (char *) uiAlloc(n * sizeof (char), "char[]");
if (WCTMB(wstr, str, n) != n) { if (WCTMB(wstr, str, n) != n)
logLastError(L"error converting from UTF-16 to UTF-8"); {
// and return an empty string logLastError(L"error converting from UTF-16 to UTF-8");
*str = '\0'; /* and return an empty string */
} *str = '\0';
}
return str; return str;
} }
@ -81,17 +83,18 @@ WCHAR *vstrf(const WCHAR *format, va_list ap)
va_copy(ap2, ap); va_copy(ap2, ap);
n = _vscwprintf(format, ap2); n = _vscwprintf(format, ap2);
va_end(ap2); va_end(ap2);
n++; // terminating L'\0' n++; /* terminating L'\0' */
buf = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]"); buf = (WCHAR *) uiAlloc(n * sizeof (WCHAR), "WCHAR[]");
// includes terminating L'\0' according to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx /* includes terminating L'\0' according
* to example in https://msdn.microsoft.com/en-us/library/xa1a1a6z.aspx */
vswprintf_s(buf, n, format, ap); vswprintf_s(buf, n, format, ap);
return buf; return buf;
} }
// Let's shove these utility routines here too. /* Let's shove these utility routines here too.
// Prerequisite: lfonly is UTF-8. * Prerequisite: lfonly is UTF-8. */
char *LFtoCRLF(const char *lfonly) char *LFtoCRLF(const char *lfonly)
{ {
size_t i; size_t i;
@ -109,25 +112,26 @@ char *LFtoCRLF(const char *lfonly)
return out; return out;
} }
// Prerequisite: s is UTF-8. /* Prerequisite: s is UTF-8. */
void CRLFtoLF(char *s) void CRLFtoLF(char *s)
{ {
char *t = s; char *t = s;
for (; *s != '\0'; s++) { for (; *s != '\0'; s++)
// be sure to preserve \rs that are genuinely there {
/* be sure to preserve \rs that are genuinely there */
if (*s == '\r' && *(s + 1) == '\n') if (*s == '\r' && *(s + 1) == '\n')
continue; continue;
*t++ = *s; *t++ = *s;
} }
*t = '\0'; *t = '\0';
// pad out the rest of t, just to be safe /* pad out the rest of t, just to be safe */
while (t != s) while (t != s)
*t++ = '\0'; *t++ = '\0';
} }
// std::to_string() always uses %f; we want %g /* std::to_string() always uses %f; we want %g
// fortunately std::iostream seems to use %g by default so * fortunately std::iostream seems to use %g by default so */
WCHAR *ftoutf16(double d) WCHAR *ftoutf16(double d)
{ {
std::wostringstream ss; std::wostringstream ss;
@ -145,6 +149,6 @@ WCHAR *itoutf16(int i)
std::wstring s; std::wstring s;
ss << i; ss << i;
s = ss.str(); // to be safe s = ss.str(); /* to be safe */
return utf16dup(s.c_str()); return utf16dup(s.c_str());
} }

View File

@ -1,13 +1,14 @@
// 14 may 2015 /* 14 may 2015 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
// The utility window is a special window that performs certain tasks internal to libui. /* The utility window is a special window that performs certain tasks internal to libui.
// It is not a message-only window, and it is always hidden and disabled. * It is not a message-only window, and it is always hidden and disabled.
// Its roles: * Its roles:
// - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent. * - It is the initial parent of all controls. When a control loses its parent, it also becomes that control's parent.
// - It handles WM_QUERYENDSESSION and console end session requests. * - It handles WM_QUERYENDSESSION and console end session requests.
// - It handles WM_WININICHANGE and forwards the message to any child windows that request it. * - It handles WM_WININICHANGE and forwards the message to any child windows that request it.
// - It handles executing functions queued to run by uiQueueMain(). * - It handles executing functions queued to run by uiQueueMain().
*/
#define utilWindowClass L"libui_utilWindowClass" #define utilWindowClass L"libui_utilWindowClass"
@ -54,7 +55,7 @@ const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor)
wc.hCursor = hDefaultCursor; wc.hCursor = hDefaultCursor;
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
if (RegisterClass(&wc) == 0) if (RegisterClass(&wc) == 0)
// see init.cpp for an explanation of the =s /* see init.cpp for an explanation of the =s */
return "=registering utility window class"; return "=registering utility window class";
utilWindow = CreateWindowExW(0, utilWindow = CreateWindowExW(0,
@ -64,7 +65,7 @@ const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor)
NULL, NULL, hInstance, NULL); NULL, NULL, hInstance, NULL);
if (utilWindow == NULL) if (utilWindow == NULL)
return "=creating utility window"; return "=creating utility window";
// and just to be safe /* and just to be safe */
EnableWindow(utilWindow, FALSE); EnableWindow(utilWindow, FALSE);
return NULL; return NULL;

View File

@ -1,4 +1,4 @@
// 6 april 2015 /* 6 april 2015 */
#include "uipriv_windows.hpp" #include "uipriv_windows.hpp"
void uiWindowsEnsureDestroyWindow(HWND hwnd) void uiWindowsEnsureDestroyWindow(HWND hwnd)
@ -35,27 +35,30 @@ void uiWindowsEnsureMoveWindowDuringResize(HWND hwnd, int x, int y, int width, i
logLastError(L"error moving window"); logLastError(L"error moving window");
} }
// do these function even error out in any case other than invalid parameters?! I thought all windows had rects /* do these function even error out in any case
* other than invalid parameters?! I thought all windows had rects */
void uiWindowsEnsureGetClientRect(HWND hwnd, RECT *r) void uiWindowsEnsureGetClientRect(HWND hwnd, RECT *r)
{ {
if (GetClientRect(hwnd, r) == 0) { if (GetClientRect(hwnd, r) == 0)
logLastError(L"error getting window client rect"); {
// zero out the rect on error just to be safe logLastError(L"error getting window client rect");
r->left = 0; /* zero out the rect on error just to be safe */
r->top = 0; r->left = 0;
r->right = 0; r->top = 0;
r->bottom = 0; r->right = 0;
} r->bottom = 0;
}
} }
void uiWindowsEnsureGetWindowRect(HWND hwnd, RECT *r) void uiWindowsEnsureGetWindowRect(HWND hwnd, RECT *r)
{ {
if (GetWindowRect(hwnd, r) == 0) { if (GetWindowRect(hwnd, r) == 0)
logLastError(L"error getting window rect"); {
// zero out the rect on error just to be safe logLastError(L"error getting window rect");
r->left = 0; /* zero out the rect on error just to be safe */
r->top = 0; r->left = 0;
r->right = 0; r->top = 0;
r->bottom = 0; r->right = 0;
} r->bottom = 0;
}
} }