diff --git a/wintable/accessibility_darwin.c b/wintable/accessibility_darwin.c
deleted file mode 100644
index d72524c..0000000
--- a/wintable/accessibility_darwin.c
+++ /dev/null
@@ -1,117 +0,0 @@
-// 9 november 2014
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// 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 <oleacc.h>
-
-struct tableAccessible {
-	IAccessibleVtbl vtbl;
-	volatile ULONG refcount;		// TODO ensure this is aligned
-	struct table *t;
-};
-
-static IAccessibleVtbl aaccessible = {
-	// IUnknkown
-	.QueryInterface = taQueryInterface,
-	.AddRef = taAddRef,
-	.Release = taRelease,
-	// IDispatch
-	.GetTypeInfoCount = taGetTypeInfoCount,
-	.GetTypeInfo = taGetTypeInfo,
-	.GetIDsOfNames = taGetIDsOfNames,
-	.Invoke = taInvoke,
-	// IAccessible
-	...
-};
-
-HRESULT STDMETHODCALLTYPE taQueryInterface(IUnknown *this, REFIID riid, void **ppvObject)
-{
-	if (ppvObject == NULL)
-		return E_POINTER;
-	// we're required to return the same pointer for IUnknown
-	// since this is a straight singly-derived interface inheritance, we can exploit the structure layout and just return the same pointer for everything
-	// at least I hope... (TODO)
-	if (IsEqualIID(riid, IID_IUnknown) ||
-		IsEqualIID(riid, IID_IDispatch) ||
-		IsEqualIID(riid, IID_IAccessible)) {
-		this->AddRef(this);
-		*ppvObject = (void *) this;
-		return S_OK;
-	}
-	// we're not making a special class for this
-	*ppvObject = NULL;
-	return E_NOINTERFACE;
-}
-
-ULONG STDMETHODCALLTYPE taAddRef(IUnknown *this)
-{
-	// TODO is the signed conversion safe?
-	return (ULONG) InterlockedIncrement((volatile LONG *) (&(((tableAccessible *) this)->refcount)));
-}
-
-ULONG STDMETHODCALLTYPE taRelease(IUnknown *this)
-{
-	ULONG rc;
-
-	rc = (ULONG) InterlockedDecrement((volatile LONG *) (&(((tableAccessible *) this)->refcount)));
-	// don't pull the refcount back out (see http://blogs.msdn.com/b/oldnewthing/archive/2013/04/25/10413997.aspx)
-	if (rc == 0)
-		free((tableAccessible *) this);
-	return rc;
-}
-
-// here's the IDispatch member functions
-// we actually /don't/ need to define any of these!
-// see also http://msdn.microsoft.com/en-us/library/windows/desktop/cc307844.aspx
-
-HRESULT STDMETHODCALLTYPE taGetTypeInfoCount(IDispatch *this, UINT *pctinfo)
-{
-	if (pctinfo == NULL)
-		return E_INVALIDARG;
-	// TODO really set this to zero?
-	*pctinfo = 0;
-	return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taGetTypeInfo(IDispatch *this, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
-{
-	if (pctinfo == NULL)
-		return E_INVALIDARG;
-	*ppTInfo = NULL;
-	// let's do this just to be safe
-	if (iTInfo == 0)
-		return DISP_E_BADINDEX;
-	return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taGetIDsOfNames(IDispatch *this, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
-{
-	// rgDispId is an array of LONGs; setting it to NULL is useless
-	// TODO should we clear the array?
-	return E_NOTIMPL;
-}
-
-HRESULT STDMETHODCALLTYPE taInvoke(IDispatch *this, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
-{
-	// TODO set anything to NULL or 0?
-	return E_NOTIMPL;
-}
-
-// ok that's it for IDispatch; now for IAccessible!
diff --git a/wintable/api.h b/wintable/api.h
deleted file mode 100644
index 5fdf599..0000000
--- a/wintable/api.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// 29 november 2014
-
-static void addColumn(struct table *t, WPARAM wParam, LPARAM lParam)
-{
-	HDITEMW item;
-
-	if (((int) wParam) >= nTableColumnTypes)
-		abort();
-
-	t->nColumns++;
-	t->columnTypes = (int *) realloc(t->columnTypes, t->nColumns * sizeof (int));
-	if (t->columnTypes == NULL)
-		abort();
-	t->columnTypes[t->nColumns - 1] = (int) wParam;
-
-	ZeroMemory(&item, sizeof (HDITEMW));
-	item.mask = HDI_WIDTH | HDI_TEXT | HDI_FORMAT;
-	item.cxy = 200;		// TODO
-	item.pszText = (WCHAR *) lParam;
-	item.fmt = HDF_LEFT | HDF_STRING;
-	if (SendMessage(t->header, HDM_INSERTITEM, (WPARAM) (t->nColumns - 1), (LPARAM) (&item)) == (LRESULT) (-1))
-		abort();
-	// TODO resize(t)?
-	redrawAll(t);
-}
-
-HANDLER(API)
-{
-	switch (uMsg) {
-	case WM_SETFONT:
-		t->font = (HFONT) wParam;
-		if (t->font == NULL)
-			t->font = t->defaultFont;
-		// also set the header font
-		SendMessageW(t->header, WM_SETFONT, wParam, lParam);
-		if (LOWORD(lParam) != FALSE) {
-			// the scrollbar page size will change so redraw that too
-			// also recalculate the header height
-			// TODO do that when this is FALSE too somehow
-			resize(t);
-			redrawAll(t);
-		}
-		*lResult = 0;
-		return TRUE;
-	case WM_GETFONT:
-		*lResult = (LRESULT) t->font;
-		return TRUE;
-	case tableAddColumn:
-		addColumn(t, wParam, lParam);
-		*lResult = 0;
-		return TRUE;
-	}
-	return FALSE;
-}
diff --git a/wintable/draw.h b/wintable/draw.h
deleted file mode 100644
index adc1e68..0000000
--- a/wintable/draw.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 30 november 2014
-
-static void resize(struct table *t)
-{
-	RECT r;
-	SCROLLINFO si;
-
-	// do this first so our scrollbar calculations can be correct
-	repositionHeader(t);
-
-	// now adjust the scrollbars
-	r = realClientRect(t);
-	t->pagesize = (r.bottom - r.top) / rowHeight(t);
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_RANGE | SIF_PAGE;
-	si.nMin = 0;
-	si.nMax = t->count - 1;
-	si.nPage = t->pagesize;
-	SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
-
-	recomputeHScroll(t);
-}
-
-// TODO alter this so that only the visible columns are redrawn
-// TODO this means rename controlSize to clientRect
-static void drawItem(struct table *t, HDC dc, intptr_t i, LONG y, LONG height, RECT controlSize)
-{
-	RECT rsel;
-	HBRUSH background;
-	int textColor;
-	WCHAR msg[100];
-	RECT headeritem;
-	intptr_t j;
-	LRESULT xoff;
-	IMAGELISTDRAWPARAMS ip;
-	POINT pt;
-
-	// TODO verify these two
-	background = (HBRUSH) (COLOR_WINDOW + 1);
-	textColor = COLOR_WINDOWTEXT;
-	if (t->selected == i) {
-		// these are the colors wine uses (http://source.winehq.org/source/dlls/comctl32/listview.c)
-		// the two for unfocused are also suggested by http://stackoverflow.com/questions/10428710/windows-forms-inactive-highlight-color
-		background = (HBRUSH) (COLOR_HIGHLIGHT + 1);
-		textColor = COLOR_HIGHLIGHTTEXT;
-		if (GetFocus() != t->hwnd) {
-			background = (HBRUSH) (COLOR_BTNFACE + 1);
-			textColor = COLOR_BTNTEXT;
-		}
-	}
-
-	// first fill the selection rect
-	// note that this already only draws the visible area
-	rsel.left = controlSize.left;
-	rsel.top = y;
-	rsel.right = controlSize.right - controlSize.left;
-	rsel.bottom = y + height;
-	if (FillRect(dc, &rsel, background) == 0)
-		abort();
-
-	// TODO double-check to see if this takes any parameters
-	xoff = SendMessageW(t->header, HDM_GETBITMAPMARGIN, 0, 0);
-	// now adjust for horizontal scrolling
-	xoff -= t->hpos;
-
-	// now draw the cells
-	if (SetTextColor(dc, GetSysColor(textColor)) == CLR_INVALID)
-		abort();
-	if (SetBkMode(dc, TRANSPARENT) == 0)
-		abort();
-	for (j = 0; j < t->nColumns; j++) {
-		if (SendMessageW(t->header, HDM_GETITEMRECT, (WPARAM) j, (LPARAM) (&headeritem)) == 0)
-			abort();
-		switch (t->columnTypes[j]) {
-		case tableColumnText:
-			rsel.left = headeritem.left + xoff;
-			rsel.top = y;
-			rsel.right = headeritem.right;
-			rsel.bottom = y + height;
-			// TODO vertical center in case the height is less than the icon height?
-			if (DrawTextExW(dc, msg, wsprintf(msg, L"Item %d", i), &rsel, DT_END_ELLIPSIS | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE, NULL) == 0)
-				abort();
-			break;
-		case tableColumnImage:
-			// TODO vertically center if image is smaller than text height
-			// TODO same for checkboxes
-			ZeroMemory(&ip, sizeof (IMAGELISTDRAWPARAMS));
-			ip.cbSize = sizeof (IMAGELISTDRAWPARAMS);
-			ip.himl = t->checkboxes;//t->imagelist;
-			ip.i = (i%8);//0;
-			ip.hdcDst = dc;
-			ip.x = headeritem.left + xoff;
-			ip.y = y;
-			ip.cx = 0;		// draw whole image
-			ip.cy = 0;
-			ip.xBitmap = 0;
-			ip.yBitmap = 0;
-			ip.rgbBk = CLR_NONE;
-			ip.fStyle = ILD_NORMAL | ILD_SCALE;		// TODO alpha-blend; ILD_DPISCALE?
-			// TODO ILS_ALPHA?
-			if (ImageList_DrawIndirect(&ip) == 0)
-				abort();
-			break;
-		case tableColumnCheckbox:
-			// TODO
-			break;
-		}
-		if (t->selected == i && t->focusedColumn == j) {
-			rsel.left = headeritem.left;
-			rsel.top = y;
-			rsel.right = headeritem.right;
-			rsel.bottom = y + height;
-			if (DrawFocusRect(dc, &rsel) == 0)
-				abort();
-		}
-	}
-}
-
-static void drawItems(struct table *t, HDC dc, RECT cliprect)
-{
-	HFONT thisfont, prevfont;
-	LONG height;
-	LONG y;
-	intptr_t i;
-	RECT controlSize;		// for filling the entire selected row
-	intptr_t first, last;
-
-	if (GetClientRect(t->hwnd, &controlSize) == 0)
-		abort();
-
-	height = rowHeight(t);
-
-	thisfont = t->font;		// in case WM_SETFONT happens before we return
-	prevfont = (HFONT) SelectObject(dc, thisfont);
-	if (prevfont == NULL)
-		abort();
-
-	// ignore anything beneath the header
-	if (cliprect.top < t->headerHeight)
-		cliprect.top = t->headerHeight;
-	// now let's pretend the header isn't there
-	// we only need it in (or rather, before) the drawItem() calls below
-	cliprect.top -= t->headerHeight;
-	cliprect.bottom -= t->headerHeight;
-
-	// see http://blogs.msdn.com/b/oldnewthing/archive/2003/07/29/54591.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/07/30/54600.aspx
-	// we need to add t->firstVisible here because cliprect is relative to the visible area
-	first = (cliprect.top / height) + t->firstVisible;
-	if (first < 0)
-		first = 0;
-	last = lastVisible(t, cliprect, height);
-
-	// now for the first y, discount firstVisible
-	y = (first - t->firstVisible) * height;
-	// and offset by the header height
-	y += t->headerHeight;
-	for (i = first; i < last; i++) {
-		drawItem(t, dc, i, y, height, controlSize);
-		y += height;
-	}
-
-	// reset everything
-	if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
-		abort();
-}
diff --git a/wintable/hscroll.h b/wintable/hscroll.h
deleted file mode 100644
index f4c3b0f..0000000
--- a/wintable/hscroll.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// 29 november 2014
-
-static void hscrollto(struct table *t, intptr_t newpos)
-{
-	SCROLLINFO si;
-	RECT scrollArea;
-
-	if (newpos < 0)
-		newpos = 0;
-	if (newpos > (t->width - t->hpagesize))
-		newpos = (t->width - t->hpagesize);
-
-	scrollArea = realClientRect(t);
-
-	// negative because ScrollWindowEx() is "backwards"
-	if (ScrollWindowEx(t->hwnd, -(newpos - t->hpos), 0,
-		&scrollArea, &scrollArea, NULL, NULL,
-		SW_ERASE | SW_INVALIDATE) == ERROR)
-		abort();
-	t->hpos = newpos;
-	// TODO text in header controls doesn't redraw?
-
-	// TODO put this in a separate function? same for vscroll?
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
-	si.nPage = t->hpagesize;
-	si.nMin = 0;
-	si.nMax = t->width - 1;		// nMax is inclusive
-	si.nPos = t->hpos;
-	SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-
-	// and finally reposition the header
-	repositionHeader(t);
-}
-
-static void hscrollby(struct table *t, intptr_t n)
-{
-	hscrollto(t, t->hpos + n);
-}
-
-// unfortunately horizontal wheel scrolling was only added in Vista
-
-static void hscroll(struct table *t, WPARAM wParam)
-{
-	SCROLLINFO si;
-	intptr_t newpos;
-
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_POS | SIF_TRACKPOS;
-	if (GetScrollInfo(t->hwnd, SB_HORZ, &si) == 0)
-		abort();
-
-	newpos = t->hpos;
-	switch (LOWORD(wParam)) {
-	case SB_LEFT:
-		newpos = 0;
-		break;
-	case SB_RIGHT:
-		newpos = t->width - t->hpagesize;
-		break;
-	case SB_LINELEFT:
-		newpos--;
-		break;
-	case SB_LINERIGHT:
-		newpos++;
-		break;
-	case SB_PAGELEFT:
-		newpos -= t->hpagesize;
-		break;
-	case SB_PAGERIGHT:
-		newpos += t->hpagesize;
-		break;
-	case SB_THUMBPOSITION:
-		newpos = (intptr_t) (si.nPos);
-		break;
-	case SB_THUMBTRACK:
-		newpos = (intptr_t) (si.nTrackPos);
-	}
-
-	hscrollto(t, newpos);
-}
-
-static void recomputeHScroll(struct table *t)
-{
-	HDITEMW item;
-	intptr_t i;
-	int width = 0;
-	RECT r;
-	SCROLLINFO si;
-
-	// TODO count dividers
-	for (i = 0; i < t->nColumns; i++) {
-		ZeroMemory(&item, sizeof (HDITEMW));
-		item.mask = HDI_WIDTH;
-		if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
-			abort();
-		width += item.cxy;
-	}
-	t->width = (intptr_t) width;
-
-	if (GetClientRect(t->hwnd, &r) == 0)
-		abort();
-	t->hpagesize = r.right - r.left;
-
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_PAGE | SIF_RANGE;
-	si.nPage = t->hpagesize;
-	si.nMin = 0;
-	si.nMax = t->width - 1;			// - 1 because endpoints inclusive
-	SetScrollInfo(t->hwnd, SB_HORZ, &si, TRUE);
-}
-
-HANDLER(hscroll)
-{
-	switch (uMsg) {
-	case WM_HSCROLL:
-		hscroll(t, wParam);
-		*lResult = 0;
-		return TRUE;
-	}
-	return FALSE;
-}
diff --git a/wintable/imagelist_windows.c b/wintable/imagelist_windows.c
deleted file mode 100644
index e194f49..0000000
--- a/wintable/imagelist_windows.c
+++ /dev/null
@@ -1,195 +0,0 @@
-// 16 august 2014
-
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// 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 <oleacc.h>
-
-enum {
-        checkboxStateChecked = 1 << 0,
-        checkboxStateHot = 1 << 1,
-        checkboxStatePushed = 1 << 2,
-        checkboxnStates = 1 << 3,
-};
-
-#define xpanic(...) abort()
-#define xpanichresult(...) abort()
-
-static UINT dfcState(int cbstate)
-{
-	UINT ret;
-
-	ret = DFCS_BUTTONCHECK;
-	if ((cbstate & checkboxStateChecked) != 0)
-		ret |= DFCS_CHECKED;
-	if ((cbstate & checkboxStateHot) != 0)
-		ret |= DFCS_HOT;
-	if ((cbstate & checkboxStatePushed) != 0)
-		ret |= DFCS_PUSHED;
-	return ret;
-}
-
-static void dfcImage(HDC dc, RECT *r, int cbState, HTHEME theme)
-{
-	if (DrawFrameControl(dc, r, DFC_BUTTON, dfcState(cbState)) == 0)
-		xpanic("error drawing checkbox image", GetLastError());
-}
-
-static void dfcSize(HDC dc, int *width, int *height, HTHEME theme)
-{
-	// there's no real metric around
-	// let's use SM_CX/YSMICON and hope for the best
-	*width = GetSystemMetrics(SM_CXSMICON);
-	*height = GetSystemMetrics(SM_CYSMICON);
-}
-
-static int themestates[checkboxnStates] = {
-	CBS_UNCHECKEDNORMAL,			// 0
-	CBS_CHECKEDNORMAL,				// checked
-	CBS_UNCHECKEDHOT,				// hot
-	CBS_CHECKEDHOT,					// checked | hot
-	CBS_UNCHECKEDPRESSED,			// pushed
-	CBS_CHECKEDPRESSED,				// checked | pushed
-	CBS_UNCHECKEDPRESSED,			// hot | pushed
-	CBS_CHECKEDPRESSED,				// checked | hot | pushed
-};
-
-static SIZE getStateSize(HDC dc, int cbState, HTHEME theme)
-{
-	SIZE s;
-	HRESULT res;
-
-	res = GetThemePartSize(theme, dc, BP_CHECKBOX, themestates[cbState], NULL, TS_DRAW, &s);
-	if (res != S_OK)
-		xpanichresult("error getting theme part size", res);
-	return s;
-}
-
-static void themeImage(HDC dc, RECT *r, int cbState, HTHEME theme)
-{
-	HRESULT res;
-
-	res = DrawThemeBackground(theme, dc, BP_CHECKBOX, themestates[cbState], r, NULL);
-	if (res != S_OK)
-		xpanichresult("error drawing checkbox image", res);
-}
-
-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 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;
-}
-
-static HIMAGELIST newCheckboxImageList(HWND hwnddc, void (*sizefunc)(HDC, int *, int *, HTHEME), void (*drawfunc)(HDC, RECT *, int, HTHEME), HTHEME theme, int *width, int *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 = 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 (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;
-}
-
-HIMAGELIST makeCheckboxImageList(HWND hwnddc, HTHEME *theme, int *width, int *height)
-{
-	if (*theme != NULL) {
-		HRESULT res;
-
-		res = CloseThemeData(*theme);
-		if (res != S_OK)
-			xpanichresult("error closing theme", res);
-		*theme = NULL;
-	}
-	// ignore error; if it can't be done, we can fall back to DrawFrameControl()
-	if (*theme == NULL)		// try to open the theme
-		*theme = OpenThemeData(hwnddc, L"button");
-	if (*theme != NULL)		// use the theme
-		return newCheckboxImageList(hwnddc, themeSize, themeImage, *theme, width, height);
-	// couldn't open; fall back
-	return newCheckboxImageList(hwnddc, dfcSize, dfcImage, *theme, width, height);
-}
diff --git a/wintable/main.c b/wintable/main.c
deleted file mode 100644
index 4f1b3e2..0000000
--- a/wintable/main.c
+++ /dev/null
@@ -1,303 +0,0 @@
-// 19 october 2014
-#define UNICODE
-#define _UNICODE
-#define STRICT
-#define STRICT_TYPED_ITEMIDS
-#define CINTERFACE
-// 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>
-extern HIMAGELIST makeCheckboxImageList(HWND hwnddc, HTHEME *theme, int *, int *);
-enum {
-        checkboxStateChecked = 1 << 0,
-        checkboxStateHot = 1 << 1,
-        checkboxStatePushed = 1 << 2,
-        checkboxnStates = 1 << 3,
-};
-#include <windowsx.h>
-#include <vsstyle.h>
-#include <vssym32.h>
-#include <oleacc.h>
-
-// #qo LIBS: user32 kernel32 gdi32 comctl32 uxtheme
-
-// TODO
-// - http://blogs.msdn.com/b/oldnewthing/archive/2003/09/09/54826.aspx (relies on the integrality parts? IDK)
-// 	- might want to http://blogs.msdn.com/b/oldnewthing/archive/2003/09/17/54944.aspx instead
-// - http://msdn.microsoft.com/en-us/library/windows/desktop/bb775574%28v=vs.85%29.aspx
-// - hscroll
-// 	- keyboard navigation
-// 		- how will this affect hot-tracking?
-// 	- automatic hscroll when scrolling columns
-// - accessibility
-// 	- must use MSAA as UI Automation is not included by default on Windows XP (and apparently requires SP3?)
-// - try horizontally scrolling the initail window and watch the selection rect corrupt itself *sometimes*
-// - preallocate t->columnTypes instead of keeping it at exactly the right size
-// - checkbox events
-// 	- space to toggle (TODO); + or = to set; - to clear (see http://msdn.microsoft.com/en-us/library/windows/desktop/bb775941%28v=vs.85%29.aspx)
-// 	- TODO figure out which notification is needed
-// - http://blogs.msdn.com/b/oldnewthing/archive/2006/01/03/508694.aspx
-// - free all allocated resources on WM_DESTROY
-// - rename lastmouse
-// 	- or perhaps do a general cleanup of the checkbox and mouse event code...
-// - figure out why initial draw pretends there is no header
-// - find places where the top-left corner of the client rect is assumed to be (0, 0)
-// - rewrite a lot of this crap to make better sense of coordinates and item counts, get rid of needless resizing and redrawing, etc.
-
-#define tableWindowClass L"gouitable"
-
-// start at WM_USER + 20 just in case for whatever reason we ever get the various dialog manager messages (see also http://blogs.msdn.com/b/oldnewthing/archive/2003/10/21/55384.aspx)
-enum {
-	// wParam - one of the type constants
-	// lParam - column name as a Unicode string
-	tableAddColumn = WM_USER + 20,
-};
-
-enum {
-	tableColumnText,
-	tableColumnImage,
-	tableColumnCheckbox,
-	nTableColumnTypes,
-};
-
-struct table {
-	HWND hwnd;
-	HFONT defaultFont;
-	HFONT font;
-	intptr_t selected;
-	intptr_t count;
-	intptr_t firstVisible;
-	intptr_t pagesize;		// in rows
-	int wheelCarry;
-	HWND header;
-	int headerHeight;
-	intptr_t nColumns;
-	HIMAGELIST imagelist;
-	int imagelistHeight;
-	intptr_t width;
-	intptr_t hpagesize;
-	intptr_t hpos;
-	HIMAGELIST checkboxes;
-	HTHEME theme;
-	int *columnTypes;
-	intptr_t focusedColumn;
-	int checkboxWidth;
-	int checkboxHeight;
-};
-
-#define HANDLER(what) static BOOL what ## Handler(struct table *t, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
-#include "util.h"
-#include "hscroll.h"
-#include "vscroll.h"
-#include "selection.h"
-#include "draw.h"
-#include "api.h"
-
-typedef BOOL (*handlerfunc)(struct table *, UINT, WPARAM, LPARAM, LRESULT *);
-
-const handlerfunc handlerfuncs[] = {
-	hscrollHandler,
-	vscrollHandler,
-	APIHandler,
-	NULL,
-};
-
-// TODO create a system where each of the above modules provide their own window procedures
-static LRESULT CALLBACK tableWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-	struct table *t;
-	handlerfunc *hf;
-	LRESULT lResult;
-	HDC dc;
-	PAINTSTRUCT ps;
-	NMHDR *nmhdr = (NMHDR *) lParam;
-	NMHEADERW *nm = (NMHEADERW *) lParam;
-
-	t = (struct table *) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
-	if (t == NULL) {
-		// we have to do things this way because creating the header control will fail mysteriously if we create it first thing
-		// (which is fine; we can get the parent hInstance this way too)
-		if (uMsg == WM_NCCREATE) {
-			CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
-
-			t = (struct table *) malloc(sizeof (struct table));
-			if (t == NULL)
-				abort();
-			ZeroMemory(t, sizeof (struct table));
-			t->hwnd = hwnd;
-			// TODO this should be a global
-			t->defaultFont = (HFONT) GetStockObject(SYSTEM_FONT);
-			if (t->defaultFont == NULL)
-				abort();
-			t->font = t->defaultFont;
-t->selected = 5;t->count=100;//TODO
-			t->header = CreateWindowExW(0,
-				WC_HEADERW, L"",
-				// TODO is HOTTRACK needed?
-				WS_CHILD | HDS_FULLDRAG | HDS_HORZ | HDS_HOTTRACK,
-				0, 0, 0, 0,
-				t->hwnd, (HMENU) 100, cs->hInstance, NULL);
-			if (t->header == NULL)
-				abort();
-{t->imagelist = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32, 1, 1);
-if(t->imagelist==NULL)abort();
-{
-HICON icon;
-int unused;
-icon = LoadIconW(NULL, IDI_ERROR);
-if(icon == NULL)abort();
-if (ImageList_AddIcon(t->imagelist, icon) == -1)abort();
-if (ImageList_GetIconSize(t->imagelist, &unused, &(t->imagelistHeight)) == 0)abort();
-}
-}
-			t->checkboxes = makeCheckboxImageList(t->hwnd, &(t->theme), &(t->checkboxWidth), &(t->checkboxHeight));
-			t->focusedColumn = -1;
-//TODO			retrack(t);
-			SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) t);
-		}
-		// even if we did the above, fall through
-		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-	}
-	for (hf = handlerfuncs; *hf != NULL; hf++)
-		if ((*hf)(t, uMsg, wParam, lParam, &lResult))
-			return lResult;
-	switch (uMsg) {
-	case WM_PAINT:
-		dc = BeginPaint(hwnd, &ps);
-		if (dc == NULL)
-			abort();
-		drawItems(t, dc, ps.rcPaint);
-		EndPaint(hwnd, &ps);
-		return 0;
-	case WM_SIZE:
-		resize(t);
-		return 0;
-	case WM_LBUTTONDOWN:
-		selectItem(t, wParam, lParam);
-		return 0;
-	case WM_SETFOCUS:
-	case WM_KILLFOCUS:
-		// all we need to do here is redraw the highlight
-		// TODO ensure giving focus works right
-		// TODO figure out hwat I meant by this
-		redrawRow(t, t->selected);
-		return 0;
-	case WM_KEYDOWN:
-		keySelect(t, wParam, lParam);
-		return 0;
-	// TODO header double-click
-	case WM_NOTIFY:
-		if (nmhdr->hwndFrom == t->header)
-			switch (nmhdr->code) {
-			// I could use HDN_TRACK but wine doesn't emit that
-			case HDN_ITEMCHANGING:
-			case HDN_ITEMCHANGED:		// TODO needed?
-				recomputeHScroll(t);
-				redrawAll(t);
-				return FALSE;
-			}
-		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-	// TODO others?
-	case WM_WININICHANGE:
-	case WM_SYSCOLORCHANGE:
-	case WM_THEMECHANGED:
-		if (ImageList_Destroy(t->checkboxes) == 0)
-			abort();
-		t->checkboxes = makeCheckboxImageList(t->hwnd, &(t->theme), &(t->checkboxWidth), &(t->checkboxHeight));
-		resize(t);		// TODO needed?
-		redrawAll(t);
-		// now defer back to DefWindowProc() in case other things are needed
-		// TODO needed?
-		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-	case WM_GETOBJECT:		// accessibility
-/*
-		if (((DWORD) lParam) == OBJID_CLIENT) {
-			TODO *server;
-			LRESULT lResult;
-
-			// TODO create the server object
-			lResult = LresultFromObject(IID_IAccessible, wParam, server);
-			if (/* TODO failure *|/)
-				abort();
-			// TODO release object
-			return lResult;
-		}
-*/
-		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-	default:
-		return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-	}
-	abort();
-	return 0;		// unreached
-}
-
-void makeTableWindowClass(void)
-{
-	WNDCLASSW wc;
-
-	ZeroMemory(&wc, sizeof (WNDCLASSW));
-	wc.lpszClassName = tableWindowClass;
-	wc.lpfnWndProc = tableWndProc;
-	wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
-	wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
-	wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);		// TODO correct?
-	wc.style = CS_HREDRAW | CS_VREDRAW;
-	wc.hInstance = GetModuleHandle(NULL);
-	if (RegisterClassW(&wc) == 0)
-		abort();
-}
-
-int main(int argc, char *argv[])
-{
-	HWND mainwin;
-	MSG msg;
-	INITCOMMONCONTROLSEX icc;
-
-	ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
-	icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
-	icc.dwICC = ICC_LISTVIEW_CLASSES;
-	if (InitCommonControlsEx(&icc) == 0)
-		abort();
-	makeTableWindowClass();
-	mainwin = CreateWindowExW(0,
-		tableWindowClass, L"Main Window",
-		WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
-		CW_USEDEFAULT, CW_USEDEFAULT,
-		400, 400,
-		NULL, NULL, GetModuleHandle(NULL), NULL);
-	if (mainwin == NULL)
-		abort();
-	SendMessageW(mainwin, tableAddColumn, tableColumnText, (LPARAM) L"Column");
-	SendMessageW(mainwin, tableAddColumn, tableColumnImage, (LPARAM) L"Column 2");
-	SendMessageW(mainwin, tableAddColumn, tableColumnCheckbox, (LPARAM) L"Column 3");
-	if (argc > 1) {
-		NONCLIENTMETRICSW ncm;
-		HFONT font;
-
-		ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW));
-		ncm.cbSize = sizeof (NONCLIENTMETRICSW);
-		if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0)
-			abort();
-		font = CreateFontIndirectW(&ncm.lfMessageFont);
-		if (font == NULL)
-			abort();
-		SendMessageW(mainwin, WM_SETFONT, (WPARAM) font, TRUE);
-	}
-	ShowWindow(mainwin, SW_SHOWDEFAULT);
-	if (UpdateWindow(mainwin) == 0)
-		abort();
-	while (GetMessageW(&msg, NULL, 0, 0) > 0) {
-		TranslateMessage(&msg);
-		DispatchMessageW(&msg);
-	}
-	return 0;
-}
diff --git a/wintable/selection.h b/wintable/selection.h
deleted file mode 100644
index 12c30d5..0000000
--- a/wintable/selection.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// 30 november 2014
-
-static void finishSelect(struct table *t, intptr_t prev)
-{
-	if (t->selected < 0)
-		t->selected = 0;
-	if (t->selected >= t->count)
-		t->selected = t->count - 1;
-
-	// always redraw the old and new rows to avoid artifacts when scrolling, even if they are the same (since the focused column may have changed)
-	redrawRow(t, prev);
-	if (prev != t->selected)
-		redrawRow(t, t->selected);
-
-	// if we need to scroll, the scrolling will force a redraw, so we don't have to worry about doing so ourselves
-	if (t->selected < t->firstVisible)
-		vscrollto(t, t->selected);
-	// note that this is not lastVisible(t) because the last visible row may only be partially visible and we want selections to make them fully visible
-	else if (t->selected >= (t->firstVisible + t->pagesize))
-		vscrollto(t, t->selected - t->pagesize + 1);
-}
-
-// TODO isolate functionality so other keyboard event handlers can run
-static void keySelect(struct table *t, WPARAM wParam, LPARAM lParam)
-{
-	intptr_t prev;
-
-	// TODO figure out correct behavior with nothing selected
-	if (t->count == 0)		// don't try to do anything if there's nothing to do
-		return;
-	prev = t->selected;
-	switch (wParam) {
-	case VK_UP:
-		t->selected--;
-		break;
-	case VK_DOWN:
-		t->selected++;
-		break;
-	case VK_PRIOR:
-		t->selected -= t->pagesize;
-		break;
-	case VK_NEXT:
-		t->selected += t->pagesize;
-		break;
-	case VK_HOME:
-		t->selected = 0;
-		break;
-	case VK_END:
-		t->selected = t->count - 1;
-		break;
-	case VK_LEFT:
-		t->focusedColumn--;
-		if (t->focusedColumn < 0)
-			if (t->nColumns == 0)		// peg at -1
-				t->focusedColumn = -1;
-			else
-				t->focusedColumn = 0;
-		break;
-	case VK_RIGHT:
-		t->focusedColumn++;
-		if (t->focusedColumn >= t->nColumns)
-			if (t->nColumns == 0)		// peg at -1
-				t->focusedColumn = -1;
-			else
-				t->focusedColumn = t->nColumns - 1;
-		break;
-	// TODO keyboard shortcuts for going to the first/last column?
-	default:
-		// don't touch anything
-		return;
-	}
-	finishSelect(t, prev);
-}
-
-// TODO rename
-static void selectItem(struct table *t, WPARAM wParam, LPARAM lParam)
-{
-	intptr_t prev;
-
-	prev = t->selected;
-	lParamToRowColumn(t, lParam, &(t->selected), &(t->focusedColumn));
-	finishSelect(t, prev);
-}
diff --git a/wintable/util.h b/wintable/util.h
deleted file mode 100644
index c12435f..0000000
--- a/wintable/util.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// 29 november 2014
-
-static LONG rowHeight(struct table *t)
-{
-	HFONT thisfont, prevfont;
-	TEXTMETRICW tm;
-	HDC dc;
-	LONG ret;
-
-	dc = GetDC(t->hwnd);
-	if (dc == NULL)
-		abort();
-	thisfont = t->font;		// in case WM_SETFONT happens before we return
-	prevfont = (HFONT) SelectObject(dc, thisfont);
-	if (prevfont == NULL)
-		abort();
-	if (GetTextMetricsW(dc, &tm) == 0)
-		abort();
-	if (SelectObject(dc, prevfont) != (HGDIOBJ) (thisfont))
-		abort();
-	if (ReleaseDC(t->hwnd, dc) == 0)
-		abort();
-	ret = tm.tmHeight;
-	if (ret < t->imagelistHeight)
-		ret = t->imagelistHeight;
-	if (ret < t->checkboxHeight)
-		ret = t->checkboxHeight;
-	return ret;
-}
-
-static void redrawAll(struct table *t)
-{
-	if (InvalidateRect(t->hwnd, NULL, TRUE) == 0)
-		abort();
-	if (UpdateWindow(t->hwnd) == 0)
-		abort();
-}
-
-static RECT realClientRect(struct table *t)
-{
-	RECT r;
-
-	if (GetClientRect(t->hwnd, &r) == 0)
-		abort();
-	r.top += t->headerHeight;
-	return r;
-}
-
-static void repositionHeader(struct table *t)
-{
-	RECT r;
-	HDLAYOUT headerlayout;
-	WINDOWPOS headerpos;
-
-	if (GetClientRect(t->hwnd, &r) == 0)		// use the whole client rect
-		abort();
-	// grow the rectangle to the left to fake scrolling
-	r.left -= t->hpos;
-	headerlayout.prc = &r;
-	headerlayout.pwpos = &headerpos;
-	if (SendMessageW(t->header, HDM_LAYOUT, 0, (LPARAM) (&headerlayout)) == FALSE)
-		abort();
-	if (SetWindowPos(t->header, headerpos.hwndInsertAfter, headerpos.x, headerpos.y, headerpos.cx, headerpos.cy, headerpos.flags | SWP_SHOWWINDOW) == 0)
-		abort();
-	t->headerHeight = headerpos.cy;
-}
-
-// this counts partially visible rows
-// for all fully visible rows use t->pagesize
-// cliprect and rowHeight must be specified here to avoid recomputing things multiple times
-static intptr_t lastVisible(struct table *t, RECT cliprect, LONG rowHeight)
-{
-	intptr_t last;
-
-	last = ((cliprect.bottom + rowHeight - 1) / rowHeight) + t->firstVisible;
-	if (last >= t->count)
-		last = t->count;
-	return last;
-}
-
-static void redrawRow(struct table *t, intptr_t row)
-{
-	RECT r;
-	intptr_t height;
-
-	r = realClientRect(t);
-	height = rowHeight(t);
-	if (row < t->firstVisible || row > lastVisible(t, r, height))		// not visible; don't bother
-		return;
-	r.top = (row - t->firstVisible) * height + t->headerHeight;
-	r.bottom = r.top + height;
-	// keep the width and height the same; it spans the client area anyway
-	if (InvalidateRect(t->hwnd, &r, TRUE) == 0)
-		abort();
-	if (UpdateWindow(t->hwnd) == 0)
-		abort();
-}
-
-static intptr_t hitTestColumn(struct table *t, int x)
-{
-	HDITEMW item;
-	intptr_t i;
-
-	// TODO count dividers
-	for (i = 0; i < t->nColumns; i++) {
-		ZeroMemory(&item, sizeof (HDITEMW));
-		item.mask = HDI_WIDTH;
-		if (SendMessageW(t->header, HDM_GETITEM, (WPARAM) i, (LPARAM) (&item)) == FALSE)
-			abort();
-		if (x < item.cxy)
-			return i;
-		x -= item.cxy;		// not yet
-	}
-	// no column
-	return -1;
-}
-
-static void lParamToRowColumn(struct table *t, LPARAM lParam, intptr_t *row, intptr_t *column)
-{
-	int x, y;
-	LONG h;
-
-	x = GET_X_LPARAM(lParam);
-	y = GET_Y_LPARAM(lParam);
-	h = rowHeight(t);
-	y += t->firstVisible * h;
-	y -= t->headerHeight;
-	y /= h;
-	if (row != NULL) {
-		*row = y;
-		if (*row >= t->count)
-			*row = -1;
-	}
-	if (column != NULL)
-		*column = hitTestColumn(t, x);
-}
diff --git a/wintable/vscroll.h b/wintable/vscroll.h
deleted file mode 100644
index 326d853..0000000
--- a/wintable/vscroll.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// 29 november 2014
-
-static void vscrollto(struct table *t, intptr_t newpos)
-{
-	SCROLLINFO si;
-	RECT scrollArea;
-
-	if (newpos < 0)
-		newpos = 0;
-	if (newpos > (t->count - t->pagesize))
-		newpos = (t->count - t->pagesize);
-
-	scrollArea = realClientRect(t);
-
-	// negative because ScrollWindowEx() is "backwards"
-	if (ScrollWindowEx(t->hwnd, 0, (-(newpos - t->firstVisible)) * rowHeight(t),
-		&scrollArea, &scrollArea, NULL, NULL,
-		SW_ERASE | SW_INVALIDATE) == ERROR)
-		abort();
-	t->firstVisible = newpos;
-
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
-	si.nPage = t->pagesize;
-	si.nMin = 0;
-	si.nMax = t->count - 1;		// nMax is inclusive
-	si.nPos = t->firstVisible;
-	SetScrollInfo(t->hwnd, SB_VERT, &si, TRUE);
-}
-
-static void vscrollby(struct table *t, intptr_t n)
-{
-	vscrollto(t, t->firstVisible + n);
-}
-
-static void wheelscroll(struct table *t, WPARAM wParam)
-{
-	int delta;
-	int lines;
-	UINT scrollAmount;
-
-	delta = GET_WHEEL_DELTA_WPARAM(wParam);
-	if (SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &scrollAmount, 0) == 0)
-		abort();
-	if (scrollAmount == WHEEL_PAGESCROLL)
-		scrollAmount = t->pagesize;
-	if (scrollAmount == 0)		// no mouse wheel scrolling (or t->pagesize == 0)
-		return;
-	// the rest of this is basically http://blogs.msdn.com/b/oldnewthing/archive/2003/08/07/54615.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2003/08/11/54624.aspx
-	// see those pages for information on subtleties
-	delta += t->wheelCarry;
-	lines = delta * ((int) scrollAmount) / WHEEL_DELTA;
-	t->wheelCarry = delta - lines * WHEEL_DELTA / ((int) scrollAmount);
-	vscrollby(t, -lines);
-}
-
-static void vscroll(struct table *t, WPARAM wParam)
-{
-	SCROLLINFO si;
-	intptr_t newpos;
-
-	ZeroMemory(&si, sizeof (SCROLLINFO));
-	si.cbSize = sizeof (SCROLLINFO);
-	si.fMask = SIF_POS | SIF_TRACKPOS;
-	if (GetScrollInfo(t->hwnd, SB_VERT, &si) == 0)
-		abort();
-
-	newpos = t->firstVisible;
-	switch (LOWORD(wParam)) {
-	case SB_TOP:
-		newpos = 0;
-		break;
-	case SB_BOTTOM:
-		newpos = t->count - t->pagesize;
-		break;
-	case SB_LINEUP:
-		newpos--;
-		break;
-	case SB_LINEDOWN:
-		newpos++;
-		break;
-	case SB_PAGEUP:
-		newpos -= t->pagesize;
-		break;
-	case SB_PAGEDOWN:
-		newpos += t->pagesize;
-		break;
-	case SB_THUMBPOSITION:
-		newpos = (intptr_t) (si.nPos);
-		break;
-	case SB_THUMBTRACK:
-		newpos = (intptr_t) (si.nTrackPos);
-	}
-
-	vscrollto(t, newpos);
-}
-
-HANDLER(vscroll)
-{
-	switch (uMsg) {
-	case WM_VSCROLL:
-		vscroll(t, wParam);
-		*lResult = 0;
-		return TRUE;
-	case WM_MOUSEWHEEL:
-		wheelscroll(t, wParam);
-		*lResult = 0;
-		return TRUE;
-	}
-	return FALSE;
-}