static LRESULT CALLBACK groupSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { LRESULT lResult; RECT r; if (sharedWndProc(hwnd, uMsg, wParam, lParam, &lResult)) return lResult; switch (uMsg) { case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGED: // don't use the WINDOWPOS rect here; the coordinates of the controls have to be in real client coordinates if (GetClientRect(hwnd, &r) == 0) xpanic("error getting client rect of Group for resizing its child Control", GetLastError()); groupResized((void *) data, r); // and chain up return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, groupSubProc, id) == FALSE) xpanic("error removing Group subclass (which was for its own event handler)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("Group", "groupSubProc()", uMsg); return 0; // unreached }
void paintControlBackground(HWND hwnd, HDC dc) { HWND parent; RECT r; POINT p, pOrig; parent = hwnd; for (;;) { parent = GetParent(parent); if (parent == NULL) xpanic("error getting parent control of control in paintControlBackground()", GetLastError()); // wine sends these messages early, yay... if (parent == msgwin) return; // skip groupboxes; they're (supposed to be) transparent if (windowClassOf(parent, L"button", NULL) != 0) break; } if (GetWindowRect(hwnd, &r) == 0) xpanic("error getting control's window rect in paintControlBackground()", GetLastError()); // the above is a window rect; convert to client rect p.x = r.left; p.y = r.top; if (ScreenToClient(parent, &p) == 0) xpanic("error getting client origin of control in paintControlBackground()", GetLastError()); if (SetWindowOrgEx(dc, p.x, p.y, &pOrig) == 0) xpanic("error moving window origin in paintControlBackground()", GetLastError()); SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT); if (SetWindowOrgEx(dc, pOrig.x, pOrig.y, NULL) == 0) xpanic("error resetting window origin in paintControlBackground()", GetLastError()); }
static HIMAGELIST newCheckboxImageList(HWND hwnddc, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme) { int width, height; int cbState; HDC dc; HIMAGELIST il; dc = GetDC(hwnddc); if (dc == NULL) xpanic("error getting DC for making the checkbox image list", GetLastError()); (*sizefunc)(dc, &width, &height, theme); il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable if (il == NULL) xpanic("error creating checkbox image list", GetLastError()); for (cbState = 0; cbState < checkboxnStates; cbState++) { HBITMAP bitmap; bitmap = makeCheckboxImageListEntry(dc, width, height, cbState, drawfunc, theme); if ((*fv_ImageList_Add)(il, bitmap, NULL) == -1) xpanic("error adding checkbox image to image list", GetLastError()); if (DeleteObject(bitmap) == 0) xpanic("error deleting checkbox bitmap", GetLastError()); } if (ReleaseDC(hwnddc, dc) == 0) xpanic("error deleting checkbox image list DC", GetLastError()); return il; }
void applyImageList(HWND hwnd, UINT uMsg, WPARAM wParam, HIMAGELIST il, HIMAGELIST old) { if (SendMessageW(hwnd, uMsg, wParam, (LPARAM) il) != (LRESULT) old) xpanic("error setting image list", GetLastError()); if (old != NULL && (*fv_ImageList_Destroy)(old) == 0) xpanic("error freeing old checkbox image list", GetLastError()); }
void repaintArea(HWND hwnd, RECT *r) { // NULL - the whole area; TRUE - have windows erase if possible if (InvalidateRect(hwnd, r, TRUE) == 0) xpanic("error flagging Area as needing repainting after event", GetLastError()); if (UpdateWindow(hwnd) == 0) xpanic("error repainting Area after event", GetLastError()); }
void textfieldSetAndShowInvalidBalloonTip(HWND hwnd, WCHAR *text) { EDITBALLOONTIP ti; ZeroMemory(&ti, sizeof (EDITBALLOONTIP)); ti.cbStruct = sizeof (EDITBALLOONTIP); ti.pszTitle = L"Invalid Input"; // TODO this is necessary for the icon to show up; figure out some language-neutral thing ti.pszText = text; ti.ttiIcon = TTI_ERROR; if (SendMessageW(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM) (&ti)) == FALSE) xpanic("error showing TextField.Invalid() balloon tip", GetLastError()); if (MessageBeep(0xFFFFFFFF) == 0) xpanic("error beeping in response to TextField.Invalid()", GetLastError()); }
HWND newAreaTextField(HWND area, void *goarea) { HWND tf; tf = CreateWindowExW(textfieldExtStyle, L"edit", L"", textfieldStyle | WS_CHILD, 0, 0, 0, 0, area, NULL, hInstance, NULL); if (tf == NULL) xpanic("error making Area TextField", GetLastError()); if ((*fv_SetWindowSubclass)(tf, areaTextFieldSubProc, 0, (DWORD_PTR) goarea) == FALSE) xpanic("error subclassing Area TextField to give it its own WM_KILLFOCUS handler", GetLastError()); return tf; }
static LRESULT CALLBACK tableSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { NMHDR *nmhdr = (NMHDR *) lParam; NMLVDISPINFOW *fill = (NMLVDISPINFO *) lParam; switch (uMsg) { case msgNOTIFY: switch (nmhdr->code) { case LVN_GETDISPINFO: tableGetCellText((void *) data, fill->item.iItem, fill->item.iSubItem, &(fill->item.pszText)); return 0; } return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); // see table.autoresize() in table_windows.go for the column autosize policy case WM_NOTIFY: // from the contained header control if (nmhdr->code == HDN_BEGINTRACK) tableStopColumnAutosize((void *) data); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, tableSubProc, id) == FALSE) xpanic("error removing Table subclass (which was for its own event handler)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("Button", "tableSubProc()", uMsg); return 0; // unreached }
static LRESULT CALLBACK checkboxSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { switch (uMsg) { case msgCOMMAND: if (HIWORD(wParam) == BN_CLICKED) { WPARAM check; // we didn't use BS_AUTOCHECKBOX (see controls_windows.go) so we have to manage the check state ourselves check = BST_CHECKED; if (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED) check = BST_UNCHECKED; SendMessage(hwnd, BM_SETCHECK, check, 0); checkboxToggled((void *) data); return 0; } return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, checkboxSubProc, id) == FALSE) xpanic("error removing Checkbox subclass (which was for its own event handler)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("Checkbox", "checkboxSubProc()", uMsg); return 0; // unreached }
void textfieldSetAndShowInvalidBalloonTip(HWND hwnd, WCHAR *text) { EDITBALLOONTIP ti; ZeroMemory(&ti, sizeof (EDITBALLOONTIP)); ti.cbStruct = sizeof (EDITBALLOONTIP); // this is required to show the error icon // this probably should be localized... ti.pszTitle = L"Invalid Input"; ti.pszText = text; ti.ttiIcon = TTI_ERROR; if (SendMessageW(hwnd, EM_SHOWBALLOONTIP, 0, (LPARAM) (&ti)) == FALSE) xpanic("error showing TextField.Invalid() balloon tip", GetLastError()); if (MessageBeep(0xFFFFFFFF) == 0) xpanic("error beeping in response to TextField.Invalid()", GetLastError()); }
// 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) xpanic("error getting name of window class in windowClassOf()", GetLastError()); 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; }
void setWindowText(HWND hwnd, LPWSTR text) { switch (SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM) text)) { case FALSE: xpanic("WM_SETTEXT failed", GetLastError()); } }
IndexChain *LookupGrid::lichain(int x, int z) { if((x<0)||(z<0)||(x>=xsz)||(z>=zsz)) xpanic("LookupGrid::lichain(%d,%d) in %dx%d-grid",x,z,xsz,zsz); return ichains[ x + (z*xsz) ]; }
void tableAutosizeColumns(HWND hwnd, int nColumns) { int i; for (i = 0; i < nColumns; i++) if (SendMessageW(hwnd, LVM_SETCOLUMNWIDTH, (WPARAM) i, (LPARAM) LVSCW_AUTOSIZE_USEHEADER) == FALSE) xpanic("error resizing columns of results list view", GetLastError()); }
RECT containerBounds(HWND hwnd) { RECT r; if (GetClientRect(hwnd, &r) == 0) xpanic("error getting container client rect for container.bounds()", GetLastError()); return r; }
static void getScrollPos(HWND hwnd, int *xpos, int *ypos) { SCROLLINFO si; ZeroMemory(&si, sizeof (SCROLLINFO)); si.cbSize = sizeof (SCROLLINFO); si.fMask = SIF_POS | SIF_TRACKPOS; if (GetScrollInfo(hwnd, SB_HORZ, &si) == 0) xpanic("error getting horizontal scroll position for Area", GetLastError()); *xpos = si.nPos; // MSDN example code reinitializes this each time, so we'll do it too just to be safe ZeroMemory(&si, sizeof (SCROLLINFO)); si.cbSize = sizeof (SCROLLINFO); si.fMask = SIF_POS | SIF_TRACKPOS; if (GetScrollInfo(hwnd, SB_VERT, &si) == 0) xpanic("error getting vertical scroll position for Area", GetLastError()); *ypos = si.nPos; }
void areaOpenTextField(HWND area, HWND textfield, int x, int y, int width, int height) { int sx, sy; int baseX, baseY; LONG unused; getScrollPos(area, &sx, &sy); x += sx; y += sy; calculateBaseUnits(textfield, &baseX, &baseY, &unused); width = MulDiv(width, baseX, 4); height = MulDiv(height, baseY, 8); if (MoveWindow(textfield, x, y, width, height, TRUE) == 0) xpanic("error moving Area TextField in Area.OpenTextFieldAt()", GetLastError()); ShowWindow(textfield, SW_SHOW); if (SetFocus(textfield) == NULL) xpanic("error giving Area TextField focus", GetLastError()); }
bool Mod_TAZ::readTAZFile(const char *fname) { FILE *f; rvulong i; if(zones != NULL) xpanic("Multiple read attempts in Mod_TAZ\n"); f=fopen(fname,"rb"); if(f==NULL) { perror(0, ERROR_FILE_ROPEN, "Cannot open `%s': %s",fname,strerror(errno)); return false; }; lprintf(1,"Reading `%s'\n",fname); fread(&size,sizeof(rvulong),1,f); zones=new Mod_TAZ_Entry[size]; MEM(zones); for(i=0;i<size;i++) { fread( &(zones[i].data), RV_TAZ_DATA_SIZE, 1,f); /* we are not interested in the rotation of the box, but rather in whether * a point is inside it. A point X is inside the box, if * * Inv(RotMatrix)*(X - center) < SizeVec * * So, we can also invert the matrices now: */ zones[i].data.rotation = zones[i].data.rotation.invert(); zones[i].mods=NULL; zones[i].owns_mods=false; if(i>0) if(zones[i].data.id < zones[i-1].data.id) xpanic("Assumption \"TAZ is sorted by ID's\" is wrong\n"); }; fclose(f); return true; }
static SIZE getAreaControlSize(HWND hwnd) { RECT rect; SIZE size; if (GetClientRect(hwnd, &rect) == 0) xpanic("error getting size of actual Area control", GetLastError()); size.cx = (LONG) (rect.right - rect.left); size.cy = (LONG) (rect.bottom - rect.top); return size; }
HIMAGELIST newImageList(int width, int height) { HIMAGELIST il; // TODO does this strip alpha? // sinni800 in irc.freenode.net/#go-nuts suggests our use of *image.RGBA makes this not so much of an issue il = (*fv_ImageList_Create)(width, height, ILC_COLOR32, 20, 20); // should be reasonable if (il == NULL) xpanic("error creating image list", GetLastError()); return il; }
void calculateBaseUnits(HWND hwnd, int *baseX, int *baseY, LONG *internalLeading) { HDC dc; HFONT prevFont; TEXTMETRICW tm; SIZE size; dc = GetDC(hwnd); if (dc == NULL) xpanic("error getting DC for preferred size calculations", GetLastError()); prevFont = (HFONT) SelectObject(dc, controlFont); if (prevFont == NULL) xpanic("error loading control font into device context for preferred size calculation", GetLastError()); if (GetTextMetricsW(dc, &tm) == 0) xpanic("error getting text metrics for preferred size calculations", GetLastError()); if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) xpanic("error getting text extent point for preferred size calculations", GetLastError()); *baseX = (int) ((size.cx / 26 + 1) / 2); *baseY = (int) tm.tmHeight; *internalLeading = tm.tmInternalLeading; if (SelectObject(dc, prevFont) != controlFont) xpanic("error restoring previous font into device context after preferred size calculations", GetLastError()); if (ReleaseDC(hwnd, dc) == 0) xpanic("error releasing DC for preferred size calculations", GetLastError()); }
void tableAppendColumn(HWND hwnd, int index, LPWSTR name) { LVCOLUMNW col; ZeroMemory(&col, sizeof (LVCOLUMNW)); col.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER; col.fmt = LVCFMT_LEFT; col.pszText = name; col.iSubItem = index; col.iOrder = index; if (SendMessageW(hwnd, LVM_INSERTCOLUMN, (WPARAM) index, (LPARAM) (&col)) == (LRESULT) -1) xpanic("error adding column to Table", GetLastError()); }
static HBITMAP makeCheckboxImageListEntry(HDC dc, int width, int height, int cbState, void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme) { BITMAPINFO bi; VOID *ppvBits; HBITMAP bitmap; RECT r; HDC drawDC; HBITMAP prevbitmap; r.left = 0; r.top = 0; r.right = width; r.bottom = height; ZeroMemory(&bi, sizeof (BITMAPINFO)); bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); bi.bmiHeader.biWidth = (LONG) width; bi.bmiHeader.biHeight = -((LONG) height); // negative height to force top-down drawing; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = (DWORD) (width * height * 4); bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); if (bitmap == NULL) xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError()); drawDC = CreateCompatibleDC(dc); if (drawDC == NULL) xpanic("error getting DC for checkbox image list bitmap", GetLastError()); prevbitmap = SelectObject(drawDC, bitmap); if (prevbitmap == NULL) xpanic("error selecting checkbox image list bitmap into DC", GetLastError()); (*drawfunc)(drawDC, &r, cbState, theme); if (SelectObject(drawDC, prevbitmap) != bitmap) xpanic("error selecting previous bitmap into checkbox image's DC", GetLastError()); if (DeleteDC(drawDC) == 0) xpanic("error deleting checkbox image's DC", GetLastError()); return bitmap; }
HWND newArea(void *data) { HWND hwnd; hwnd = CreateWindowExW( 0, areaWindowClass, L"", WS_HSCROLL | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_TABSTOP, CW_USEDEFAULT, CW_USEDEFAULT, 100, 100, msgwin, NULL, hInstance, data); if (hwnd == NULL) xpanic("container creation failed", GetLastError()); return hwnd; }
static void themeSize(HDC dc, int *width, int *height, HTHEME theme) { SIZE size; int cbState; size = getStateSize(dc, 0, theme); for (cbState = 1; cbState < checkboxnStates; cbState++) { SIZE against; against = getStateSize(dc, cbState, theme); if (size.cx != against.cx || size.cy != against.cy) xpanic("size mismatch in checkbox states", GetLastError()); } *width = (int) size.cx; *height = (int) size.cy; }
static LRESULT CALLBACK areaTextFieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { switch (uMsg) { case WM_KILLFOCUS: ShowWindow(hwnd, SW_HIDE); areaTextFieldDone((void *) data); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, areaTextFieldSubProc, id) == FALSE) xpanic("error removing Area TextField subclass (which was for handling WM_KILLFOCUS)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("Area TextField", "areaTextFieldSubProc()", uMsg); return 0; // unreached }
bool NameList::add(const char *name, bool dupCheck/*=false*/) { if(!name) xpanic("adding NULL name"); if(cnt==max) grow(); names[cnt]=strdup(name); MEM(names[cnt]); touched[cnt]=false; cnt++; if(dupCheck) { for(int i=0; i<cnt-1; i++) if(!strcmp(name, names[i])) return true; } return false; }
static LRESULT CALLBACK buttonSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { switch (uMsg) { case msgCOMMAND: if (HIWORD(wParam) == BN_CLICKED) { buttonClicked((void *) data); return 0; } return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, buttonSubProc, id) == FALSE) xpanic("error removing Button subclass (which was for its own event handler)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("Button", "buttonSubProc()", uMsg); return 0; // unreached }
static LRESULT CALLBACK textfieldSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR id, DWORD_PTR data) { switch (uMsg) { case msgCOMMAND: if (HIWORD(wParam) == EN_CHANGE) { textfieldChanged((void *) data); return 0; } return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); case WM_NCDESTROY: if ((*fv_RemoveWindowSubclass)(hwnd, textfieldSubProc, id) == FALSE) xpanic("error removing TextField subclass (which was for its own event handler)", GetLastError()); return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); default: return (*fv_DefSubclassProc)(hwnd, uMsg, wParam, lParam); } xmissedmsg("TextField", "textfieldSubProc()", uMsg); return 0; // unreached }
HBITMAP unscaledBitmap(void *i, intptr_t dx, intptr_t dy) { BITMAPINFO bi; VOID *ppvBits; HBITMAP bitmap; ZeroMemory(&bi, sizeof (BITMAPINFO)); bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); bi.bmiHeader.biWidth = (LONG) dx; bi.bmiHeader.biHeight = -((LONG) dy); // negative height to force top-down drawing; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = (DWORD) (dx * dy * 4); bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &ppvBits, 0, 0); if (bitmap == NULL) xpanic("error creating HBITMAP for unscaled ImageList image copy", GetLastError()); dotoARGB(i, (void *) ppvBits); return bitmap; }