diff --git a/src/conio/win32gdi.c b/src/conio/win32gdi.c
index 384af820a493b9d57d118ded6a3498fae78c20f9..1386443de8f16d75f79b4fd4aef819aaab9462be 100644
--- a/src/conio/win32gdi.c
+++ b/src/conio/win32gdi.c
@@ -8,15 +8,21 @@
 #include "win32cio.h"
 #include "scale.h"
 
-HBITMAP bmp;
-HWND win;
-HANDLE rch;
-HANDLE wch;
+static HWND win;
+static HANDLE rch;
+static HANDLE wch;
+
+static FILE *debug;
+static uint8_t *title;
+
+#define WM_USER_INVALIDATE WM_USER
+#define WM_USER_SETSIZE (WM_USER + 1)
+#define WM_USER_SETPOS (WM_USER + 2)
 
 #define LCS_WINDOWS_COLOR_SPACE 0x57696E20
 
 // Used to create a DI bitmap from bitmap_con data
-BITMAPV5HEADER b5hdr = {
+static BITMAPV5HEADER b5hdr = {
 	.bV5Size = sizeof(BITMAPV5HEADER),
 	.bV5Width = 640,
 	.bV5Height = -400,
@@ -34,12 +40,41 @@ BITMAPV5HEADER b5hdr = {
 extern HINSTANCE WinMainHInst;
 static struct rectlist *update_list = NULL;
 static struct rectlist *update_list_tail = NULL;
+static struct rectlist *last = NULL;
+static struct rectlist *next = NULL;
 static pthread_mutex_t gdi_headlock;
-static pthread_mutex_t bmp_lock;
-static int bitmap_width,bitmap_height;
+static pthread_mutex_t rect_lock;
 
 // Internal implementation
 
+static struct rectlist *
+get_rect(void)
+{
+	struct rectlist *ret;
+	pthread_mutex_lock(&rect_lock);
+	if (next != NULL) {
+		if (last != NULL)
+			bitmap_drv_free_rect(last);
+		last = next;
+		ret = next;
+		next = NULL;
+	}
+	else
+		ret = last;
+	pthread_mutex_unlock(&rect_lock);
+	return ret;
+}
+
+static void
+next_rect(struct rectlist *rect)
+{
+	pthread_mutex_lock(&rect_lock);
+	if (next != NULL)
+		bitmap_drv_free_rect(next);
+	next = rect;
+	pthread_mutex_unlock(&rect_lock);
+}
+
 static void
 add_key(uint16_t key)
 {
@@ -47,6 +82,7 @@ add_key(uint16_t key)
 	uint8_t *bp = buf;
 	DWORD added;
 	DWORD remain;
+
 	if (key < 256) {
 		buf[0] = key;
 		remain = 1;
@@ -72,31 +108,40 @@ sp_to_codepoint(uint16_t high, uint16_t low)
 static LRESULT CALLBACK
 gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 	PAINTSTRUCT ps;
-	HBITMAP obmp;
-	HDC memDC;
-	HDC winDC;
+	HBITMAP di;
+	static HDC memDC = NULL;
 	WPARAM highpair;
 	uint32_t cp;
 	uint8_t ch;
 	uint16_t repeat;
 	uint16_t i;
 	bool alt;
+	HDC winDC;
+	struct rectlist *list;
+	int w,h;
 
 	switch(msg) {
 		case WM_PAINT:
+			list = get_rect();
+			if (list == NULL)
+				return 0;
 			winDC = BeginPaint(hwnd, &ps);
-			memDC = CreateCompatibleDC(winDC);
-			pthread_mutex_lock(&bmp_lock);
-			obmp = SelectObject(memDC, bmp);
+			if (memDC == NULL)
+				memDC = CreateCompatibleDC(winDC);
+			b5hdr.bV5Width = list->rect.width;
+			b5hdr.bV5Height = -list->rect.height;
+			b5hdr.bV5SizeImage = list->rect.width * list->rect.height * 4;
+			di = CreateDIBitmap(winDC, (BITMAPINFOHEADER *)&b5hdr, CBM_INIT, list->data, (BITMAPINFO *)&b5hdr, 0/*DIB_RGB_COLORS*/);
+			di = SelectObject(memDC, di);
 			pthread_mutex_lock(&vstatlock);
-			//BitBlt(winDC, 0, 0, vstat.winwidth, vstat.winheight, memDC, 0, 0, SRCCOPY);
-			StretchBlt(winDC, 0, 0, vstat.winwidth, vstat.winheight, memDC, 0, 0, vstat.scrnwidth, vstat.scrnheight, SRCCOPY);
+			w = vstat.winwidth;
+			h = vstat.winheight;
 			pthread_mutex_unlock(&vstatlock);
-			SelectObject(memDC, obmp);
-			pthread_mutex_unlock(&bmp_lock);
-			DeleteDC(memDC);
+			StretchBlt(winDC, 0, 0, w, h, memDC, 0, 0, list->rect.width, list->rect.height, SRCCOPY);
+			di = SelectObject(memDC, di);
+			DeleteObject(di);
 			EndPaint(hwnd, &ps);
-			break;
+			return 0;
 		case WM_DESTROY:
 			PostQuitMessage(0);
 			return 0;
@@ -125,24 +170,6 @@ gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
 	return DefWindowProcW(hwnd, msg, wParam, lParam);
 }
 
-// Must be called with vstatlock held
-static void
-setup_bitmaps(void)
-{
-	HDC winDC;
-
-	pthread_mutex_lock(&bmp_lock);
-	if (bmp)
-		DeleteObject(bmp);
-	winDC = GetDC(win);
-	bmp = CreateCompatibleBitmap(winDC, vstat.scrnwidth, vstat.scrnheight);
-	ReleaseDC(win, winDC);
-	pthread_mutex_unlock(&bmp_lock);
-	b5hdr.bV5Width = vstat.scrnwidth;
-	b5hdr.bV5Height = -vstat.scrnheight;
-	b5hdr.bV5SizeImage = b5hdr.bV5Width * b5hdr.bV5Height * 4;
-}
-
 #define WMOD_CTRL     1
 #define WMOD_LCTRL    2
 #define WMOD_RCTRL    4
@@ -156,70 +183,90 @@ magic_message(MSG msg)
 	size_t i;
 	uint8_t set = 0;
 	int *hack;
+	RECT r;
 
-	// TODO: When window gets focus, poll mods... *sigh*
-	// TODO: Check "extended" for RCTRL and RSHIFT
-	if (msg.message == WM_KEYDOWN || msg.message == WM_KEYUP || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) {
-		switch (msg.wParam) {
-			case VK_CONTROL:
-				set = WMOD_CTRL;
-				break;
-			case VK_LCONTROL:
-				set = WMOD_LCTRL;
-				break;
-			case VK_RCONTROL:
-				set = WMOD_RCTRL;
-				break;
-			case VK_SHIFT:
-				set = WMOD_SHIFT;
-				break;
-			case VK_LSHIFT:
-				set = WMOD_LSHIFT;
-				break;
-			case VK_RSHIFT:
-				set = WMOD_RSHIFT;
-				break;
-		}
-		if (set) {
-			if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
-				mods |= set;
-			else
-				mods &= ~set;
-			return false;
-		}
-		if (msg.message == WM_KEYUP)
-			return false;
-		while (keyval[i].VirtualKeyCode != 0) {
-			if (keyval[i].VirtualKeyCode == msg.wParam)
-				break;
-			i++;
-		}
-		if (keyval[i].VirtualKeyCode != 0) {
-			if (msg.lParam & (0x2000)) {
-				if (keyval[i].ALT > 255) {
-					add_key(keyval[i].ALT);
-					return true;
-				}
-			}
-			else if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) {
-				if (keyval[i].CTRL > 255) {
-					add_key(keyval[i].CTRL);
-					return true;
-				}
+	switch(msg.message) {
+		case WM_USER_INVALIDATE:
+			InvalidateRect(win, NULL, FALSE);
+			return true;
+		case WM_USER_SETSIZE:
+			pthread_mutex_lock(&vstatlock);
+			// Now make the inside of the window the size we want (sigh)
+			r.left = r.top = 0;
+			r.right = vstat.winwidth = msg.wParam;
+			r.bottom = vstat.winheight = msg.lParam;
+			pthread_mutex_unlock(&vstatlock);
+			AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
+			SetWindowPos(win, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER);
+			return true;
+		case WM_USER_SETPOS:
+			SetWindowPos(win, NULL, msg.wParam, msg.lParam, 0, 0, SWP_NOSIZE|SWP_NOOWNERZORDER|SWP_NOZORDER);
+			return true;
+		case WM_KEYDOWN:
+		case WM_KEYUP:
+		case WM_SYSKEYDOWN:
+		case WM_SYSKEYUP:
+			switch (msg.wParam) {
+				case VK_CONTROL:
+					set = WMOD_CTRL;
+					break;
+				case VK_LCONTROL:
+					set = WMOD_LCTRL;
+					break;
+				case VK_RCONTROL:
+					set = WMOD_RCTRL;
+					break;
+				case VK_SHIFT:
+					set = WMOD_SHIFT;
+					break;
+				case VK_LSHIFT:
+					set = WMOD_LSHIFT;
+					break;
+				case VK_RSHIFT:
+					set = WMOD_RSHIFT;
+					break;
 			}
-			else if (mods & (WMOD_SHIFT | WMOD_LSHIFT | WMOD_RSHIFT)) {
-				if (keyval[i].Shift > 255) {
-					add_key(keyval[i].Shift);
-					return true;
-				}
+			if (set) {
+				if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
+					mods |= set;
+				else
+					mods &= ~set;
+				return false;
 			}
-			else {
-				if (keyval[i].Key > 255) {
-					add_key(keyval[i].Key);
-					return true;
+
+			if (msg.message == WM_KEYUP)
+				return false;
+
+			for (i = 0; keyval[i].VirtualKeyCode != 0; i++) {
+				if (keyval[i].VirtualKeyCode == msg.wParam) {
+					if (msg.lParam & (0x2000)) {
+						if (keyval[i].ALT > 255) {
+							add_key(keyval[i].ALT);
+							return true;
+						}
+					}
+					else if (mods & (WMOD_CTRL | WMOD_LCTRL | WMOD_RCTRL)) {
+						if (keyval[i].CTRL > 255) {
+							add_key(keyval[i].CTRL);
+							return true;
+						}
+					}
+					else if (mods & (WMOD_SHIFT | WMOD_LSHIFT | WMOD_RSHIFT)) {
+						if (keyval[i].Shift > 255) {
+							add_key(keyval[i].Shift);
+							return true;
+						}
+					}
+					else {
+						if (keyval[i].Key > 255) {
+							add_key(keyval[i].Key);
+							return true;
+						}
+					}
+					break;
 				}
 			}
-		}
+			break;
 	}
 
 	return false;
@@ -241,18 +288,17 @@ gdi_thread(void *arg)
 	wc.hCursor       = LoadCursor(0, IDC_IBEAM);
 	wc.hbrBackground = NULL;
 	wc.lpszMenuName  = NULL;
-	wc.lpszClassName = L"SyncTERM";
+	wc.lpszClassName = L"SyncConsole";
 
 	RegisterClassW(&wc);
 	pthread_mutex_lock(&vstatlock);
-	setup_bitmaps();
 	// Now make the inside of the window the size we want (sigh)
 	r.left = r.top = 0;
 	r.right = vstat.winwidth;
 	r.bottom = vstat.winheight;
 	pthread_mutex_unlock(&vstatlock);
 	AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE);
-	win = CreateWindowW(wc.lpszClassName, L"SyncTERM", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, wc.hInstance, NULL);
+	win = CreateWindowW(wc.lpszClassName, L"SyncConsole", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, r.right - r.left, r.bottom - r.top, NULL, NULL, wc.hInstance, NULL);
 
 	while (GetMessage(&msg, NULL, 0, 0)) {
 		if (!magic_message(msg)) {
@@ -271,7 +317,7 @@ gdi_thread(void *arg)
 int
 gdi_kbhit(void)
 {
-	DWORD avail;
+	DWORD avail = 0;
 
 	PeekNamedPipe(rch, NULL, 0, NULL, &avail, NULL);
 	return (avail > 0);
@@ -283,15 +329,16 @@ gdi_getch(void)
 	uint8_t ch;
 	DWORD got;
 
-	do {
-		ReadFile(rch, &ch, 1, &got, NULL);
-	} while (got == 0);
+	ReadFile(rch, &ch, 1, &got, NULL);
+	if (got == 0)
+		return 0;
 	return ch;
 }
 
 void
 gdi_beep(void)
 {
+	MessageBeep(MB_ICONWARNING);
 }
 
 void
@@ -311,7 +358,7 @@ gdi_textmode(int mode)
 
 	pthread_mutex_lock(&vstatlock);
 	oldcols = vstat.cols;
-	bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
+	bitmap_drv_init_mode(mode, NULL, NULL);
 	if (vstat.scrnwidth > 0) {
 		for (scaling = 1; (scaling + 1) * vstat.scrnwidth < vstat.winwidth; scaling++)
 			;
@@ -341,7 +388,10 @@ gdi_textmode(int mode)
 		vstat.winwidth = vstat.scrnwidth;
 	if (vstat.winheight < vstat.scrnheight)
 		vstat.winheight = vstat.scrnheight;
+	// TODO: This is called before there's a window...
+	gdi_setwinsize(vstat.winwidth, vstat.winheight);
 	pthread_mutex_unlock(&vstatlock);
+	bitmap_drv_request_pixels();
 
 	return;
 }
@@ -352,8 +402,19 @@ gdi_setname(const char *name)
 }
 
 void
-gdi_settitle(const char *title)
+gdi_settitle(const char *newTitle)
 {
+	uint8_t *utf8;
+	size_t sz;
+
+	free(title);
+	utf8 = cp_to_utf8(getcodepage(), newTitle, strlen(newTitle), NULL);
+	// Overkill
+	sz = strlen(utf8) * 4;
+	title = malloc(sz);
+	if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, (LPWSTR)title, sz / 2))
+		PostMessageW(win, WM_SETTEXT, 0, (LPARAM)title);
+	free(utf8);
 }
 
 void
@@ -375,6 +436,19 @@ gdi_getcliptext(void)
 int
 gdi_get_window_info(int *width, int *height, int *xpos, int *ypos)
 {
+	pthread_mutex_lock(&vstatlock);
+	if(width)
+		*width=vstat.winwidth;
+	if(height)
+		*height=vstat.winheight;
+	// TODO
+	if(xpos)
+		*xpos=0;
+	if(ypos)
+		*ypos=0;
+	pthread_mutex_unlock(&vstatlock);
+	
+	return(1);
 }
 
 int
@@ -388,7 +462,7 @@ gdi_init(int mode)
 	_beginthread(gdi_thread, 0, NULL);
 
 	cio_api.mode=CIOLIB_MODE_GDI;
-	FreeConsole();
+	//FreeConsole();
 	cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
 	return(0);
 }
@@ -396,8 +470,9 @@ gdi_init(int mode)
 int
 gdi_initciolib(int mode)
 {
+debug = fopen("gdi.log", "w");
 	pthread_mutex_init(&gdi_headlock, NULL);
-	pthread_mutex_init(&bmp_lock, NULL);
+	pthread_mutex_init(&rect_lock, NULL);
 
 	return(gdi_init(mode));
 }
@@ -421,9 +496,6 @@ gdi_flush(void)
 {
 	struct rectlist *list;
 	struct rectlist *old_next;
-	HBITMAP di;
-	HDC mDC1, mDC2, winDC;
-	HBITMAP obmp1, obmp2;
 
 	pthread_mutex_lock(&gdi_headlock);
 	list = update_list;
@@ -432,25 +504,11 @@ gdi_flush(void)
 	for (; list; list = old_next) {
 		old_next = list->next;
 		if (list->next == NULL) {
-			// Create the DI bitmap and blit to bitmap, then update
-			winDC = GetDC(win);
-			mDC1 = CreateCompatibleDC(winDC);
-			mDC2 = CreateCompatibleDC(mDC1);
-			di = CreateDIBitmap(winDC, (BITMAPINFOHEADER *)&b5hdr, CBM_INIT, list->data, (BITMAPINFO *)&b5hdr, 0/*DIB_RGB_COLORS*/);
-			ReleaseDC(win, winDC);
-			obmp1 = SelectObject(mDC1, di);
-			pthread_mutex_lock(&bmp_lock);
-			obmp2 = SelectObject(mDC2, bmp);
-			BitBlt(mDC2, list->rect.x, list->rect.y, list->rect.width, list->rect.height, mDC1, 0, 0, SRCCOPY);
-			SelectObject(mDC1, obmp1);
-			SelectObject(mDC2, obmp2);
-			pthread_mutex_unlock(&bmp_lock);
-			DeleteObject(di);
-			DeleteDC(mDC2);
-			DeleteDC(mDC1);
-			InvalidateRect(win, NULL, FALSE);
+			next_rect(list);
+			PostMessageW(win, WM_USER_INVALIDATE, 0, 0);
 		}
-		bitmap_drv_free_rect(list);
+		else
+			bitmap_drv_free_rect(list);
 	}
 }
 
@@ -468,7 +526,7 @@ gdi_getscaling(void)
 int
 gdi_mousepointer(enum ciolib_mouse_ptr type)
 {
-	return -1;// 0 on success
+	return 0;
 }
 
 int
@@ -486,9 +544,11 @@ gdi_hidemouse(void)
 void
 gdi_setwinposition(int x, int y)
 {
+	PostMessageW(win, WM_USER_SETPOS, x, y);
 }
 
 void
 gdi_setwinsize(int w, int h)
 {
+	PostMessageW(win, WM_USER_SETSIZE, w, h);
 }