diff --git a/src/conio/Common.gmake b/src/conio/Common.gmake
index 3fda06dc42f60c3ffd521a0890530d90abe7beae..136cc2c299099b088ec37dd2a6cb18a288985721 100644
--- a/src/conio/Common.gmake
+++ b/src/conio/Common.gmake
@@ -63,6 +63,10 @@ ifneq ($(os),win32)
 else
  NO_X			 :=  1
  CIOLIB-MT_CFLAGS        +=  -DDISABLE_X11=1
+ ifdef WITH_GDI
+  CIOLIB-MT_LIBS += -lgdi32
+  CIOLIB-MT_CFLAGS += -DWITH_GDI
+ endif
  ifdef USE_SDL
   WITH_SDL := 1
  endif
diff --git a/src/conio/GNUmakefile b/src/conio/GNUmakefile
index fb1dd532bedfde2f6218b217e286c27c5aee2ac3..1e4840e200ad9772d89e7013bd68cc300c4288b1 100644
--- a/src/conio/GNUmakefile
+++ b/src/conio/GNUmakefile
@@ -5,6 +5,7 @@ include $(SRC_ROOT)/build/Common.gmake	# defines clean and output directory rule
 CFLAGS += $(XPDEV-MT_CFLAGS) $(HASH_CFLAGS) $(ENCODE_CFLAGS) $(CIOLIB-MT_CFLAGS)
 
 ifeq ($(os),win32)
+ OBJS	+=	$(MTOBJODIR)$(DIRSEP)win32gdi$(OFILE)
  OBJS	+=	$(MTOBJODIR)$(DIRSEP)SDL_win32_main$(OFILE)
  OBJS	+=	$(MTOBJODIR)$(DIRSEP)win32cio$(OFILE)
  OBJS	+=	$(MTOBJODIR)$(DIRSEP)ciolib_res$(OFILE)
diff --git a/src/conio/SDL_win32_main.c b/src/conio/SDL_win32_main.c
index 96f87f245a5378b395da1b5f2da8693a19a29476..fe6f83ab37f0bee1088d84a1a5f93d4add6ce117 100644
--- a/src/conio/SDL_win32_main.c
+++ b/src/conio/SDL_win32_main.c
@@ -107,6 +107,7 @@ static int console_main(int argc, char *argv[], char **env)
 	return(n);
 }
 
+HINSTANCE WinMainHInst;
 /* This is where execution begins [windowed apps] */
 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
 {
@@ -116,6 +117,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
 	char *cmdline;
 	char *bufp;
 
+	WinMainHInst = hInst;
 	/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
 	   keep them open.  This is a hack.. hopefully it will be fixed 
 	   someday.  DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
diff --git a/src/conio/ciolib.c b/src/conio/ciolib.c
index 0cac18b53008709dc8b92b2c8e38e289db9d3987..d6b544d72d5da175323cfd54bee6462cb1c20979 100644
--- a/src/conio/ciolib.c
+++ b/src/conio/ciolib.c
@@ -50,6 +50,9 @@
 #define CIOLIB_NO_MACROS
 #include "ciolib.h"
 
+#if defined(WITH_GDI)
+ #include "win32gdi.h"
+#endif
 #if defined(WITH_SDL)
  #include "sdl_con.h"
  #include "sdlfuncs.h"
@@ -150,6 +153,57 @@ int sdl_video_initialized = 0;
 
 #define CIOLIB_INIT()		{ if(initialized != 1) initciolib(CIOLIB_MODE_AUTO); }
 
+#if defined(WITH_GDI)
+static int try_gdi_init(int mode)
+{
+	if(!gdi_initciolib(mode)) {
+		cio_api.mouse=1;
+		cio_api.puttext=bitmap_puttext;
+		cio_api.vmem_puttext=bitmap_vmem_puttext;
+		cio_api.vmem_gettext=bitmap_vmem_gettext;
+		cio_api.gotoxy=bitmap_gotoxy;
+		cio_api.setcursortype=bitmap_setcursortype;
+		cio_api.setfont=bitmap_setfont;
+		cio_api.getfont=bitmap_getfont;
+		cio_api.loadfont=bitmap_loadfont;
+		cio_api.movetext=bitmap_movetext;
+		cio_api.clreol=bitmap_clreol;
+		cio_api.clrscr=bitmap_clrscr;
+		cio_api.getcustomcursor=bitmap_getcustomcursor;
+		cio_api.setcustomcursor=bitmap_setcustomcursor;
+		cio_api.getvideoflags=bitmap_getvideoflags;
+		cio_api.setvideoflags=bitmap_setvideoflags;
+
+		cio_api.kbhit=gdi_kbhit;
+		cio_api.getch=gdi_getch;
+		cio_api.textmode=gdi_textmode;
+		cio_api.showmouse=gdi_showmouse;
+		cio_api.hidemouse=gdi_hidemouse;
+		cio_api.setname=gdi_setname;
+		cio_api.seticon=gdi_seticon;
+		cio_api.settitle=gdi_settitle;
+		cio_api.copytext=gdi_copytext;
+		cio_api.getcliptext=gdi_getcliptext;
+		cio_api.get_window_info=gdi_get_window_info;
+		cio_api.setwinsize=gdi_setwinsize;
+		cio_api.setwinposition=gdi_setwinposition;
+		cio_api.setpalette=bitmap_setpalette;
+		cio_api.attr2palette=bitmap_attr2palette;
+		cio_api.setpixel=bitmap_setpixel;
+		cio_api.getpixels=bitmap_getpixels;
+		cio_api.setpixels=bitmap_setpixels;
+		cio_api.get_modepalette=bitmap_get_modepalette;
+		cio_api.set_modepalette=bitmap_set_modepalette;
+		cio_api.map_rgb = bitmap_map_rgb;
+		cio_api.replace_font = bitmap_replace_font;
+		cio_api.beep = gdi_beep;
+		cio_api.mousepointer=gdi_mousepointer;
+		return(1);
+	}
+	return(0);
+}
+#endif
+
 #if defined(WITH_SDL)
 static int try_sdl_init(int mode)
 {
@@ -405,6 +459,9 @@ CIOLIBEXPORT int initciolib(int mode)
 #ifndef NO_X
 			if(!try_x_init(mode))
 #endif
+#ifdef _WIN32
+			if (!try_gdi_init(mode))
+#endif
 #if defined(WITH_SDL)
 				if(!try_sdl_init(CIOLIB_MODE_SDL))
 #endif
diff --git a/src/conio/ciolib.h b/src/conio/ciolib.h
index 8bc992b32ccf646ad891f32a65b331df35631af3..5edd9c417f922b97a945e9264c8db5544f91d9ac 100644
--- a/src/conio/ciolib.h
+++ b/src/conio/ciolib.h
@@ -78,6 +78,7 @@ enum {
 	,CIOLIB_MODE_CONIO_FULLSCREEN
 	,CIOLIB_MODE_SDL
 	,CIOLIB_MODE_SDL_FULLSCREEN
+	,CIOLIB_MODE_GDI
 };
 
 enum ciolib_mouse_ptr {
diff --git a/src/conio/win32gdi.c b/src/conio/win32gdi.c
new file mode 100644
index 0000000000000000000000000000000000000000..6e6f02c0fe9060ee1f6830e929dacac47a08a5dc
--- /dev/null
+++ b/src/conio/win32gdi.c
@@ -0,0 +1,347 @@
+#include <windows.h>
+#include <stdio.h>
+
+#define BITMAP_CIOLIB_DRIVER
+#include "win32gdi.h"
+#include "bitmap_con.h"
+#include "scale.h"
+
+HBITMAP bmp;
+HWND win;
+FILE *debug;
+
+#define LCS_WINDOWS_COLOR_SPACE 0x57696E20
+
+// Used to create a DI bitmap from bitmap_con data
+BITMAPV5HEADER b5hdr = {
+	.bV5Size = sizeof(BITMAPV5HEADER),
+	.bV5Width = 640,
+	.bV5Height = -400,
+	.bV5Planes = 1,
+	.bV5BitCount = 32,
+	.bV5Compression = BI_BITFIELDS,
+	.bV5SizeImage = 640 * 400 * 4,
+	.bV5RedMask = 0x00ff0000,
+	.bV5GreenMask = 0x0000ff00,
+	.bV5BlueMask = 0x000000ff,
+	.bV5CSType = LCS_WINDOWS_COLOR_SPACE,
+	.bV5Intent = LCS_GM_BUSINESS,
+};
+
+extern HINSTANCE WinMainHInst;
+static struct rectlist *update_list = NULL;
+static struct rectlist *update_list_tail = NULL;
+static pthread_mutex_t gdi_headlock;
+static pthread_mutex_t bmp_lock;
+static int bitmap_width,bitmap_height;
+
+// Internal implementation
+
+static LRESULT CALLBACK
+gdi_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+	PAINTSTRUCT ps;
+	HBITMAP obmp;
+	HDC memDC;
+	HDC winDC;
+
+	switch(msg) {
+		case WM_PAINT:
+			winDC = BeginPaint(hwnd, &ps);
+			memDC = CreateCompatibleDC(winDC);
+			pthread_mutex_lock(&bmp_lock);
+			obmp = SelectObject(memDC, bmp);
+			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);
+			pthread_mutex_unlock(&vstatlock);
+			SelectObject(memDC, obmp);
+			pthread_mutex_unlock(&bmp_lock);
+			DeleteDC(memDC);
+			EndPaint(hwnd, &ps);
+			break;
+		case WM_DESTROY:
+			PostQuitMessage(0);
+			return 0;
+	}
+
+	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;
+}
+
+static void
+gdi_thread(void *arg)
+{
+	WNDCLASSW wc = {0};
+	MSG  msg;
+	RECT r;
+
+	SetThreadName("GDI Events");
+
+	wc.style = CS_HREDRAW | CS_VREDRAW;
+	wc.lpfnWndProc   = gdi_WndProc;
+	wc.hInstance     = WinMainHInst;
+	//wc.hIcon         = ICON;        // TODO: Icon from ciolib.rc
+	wc.hCursor       = LoadCursor(0, IDC_IBEAM);
+	wc.hbrBackground = NULL;
+	wc.lpszMenuName  = NULL;
+	wc.lpszClassName = L"SyncTERM";
+
+	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);
+
+	while (GetMessage(&msg, NULL, 0, 0)) {
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+	// This may not be necessary...
+	DestroyWindow(win);
+	UnregisterClassW(wc.lpszClassName, NULL);
+}
+
+// Public API
+
+int
+gdi_kbhit(void)
+{
+	return 0;
+}
+
+int
+gdi_getch(void)
+{
+	return 0;
+}
+
+void
+gdi_beep(void)
+{
+}
+
+void
+gdi_textmode(int mode)
+{
+	int oldcols;
+	int scaling = 1;
+
+	if (mode != CIOLIB_MODE_CUSTOM) {
+		pthread_mutex_lock(&vstatlock);
+		if (mode == vstat.mode) {
+			pthread_mutex_unlock(&vstatlock);
+			return;
+		}
+		pthread_mutex_unlock(&vstatlock);
+	}
+
+	pthread_mutex_lock(&vstatlock);
+	oldcols = vstat.cols;
+	bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
+	if (vstat.scrnwidth > 0) {
+		for (scaling = 1; (scaling + 1) * vstat.scrnwidth < vstat.winwidth; scaling++)
+			;
+	}
+	vstat.winwidth = vstat.scrnwidth * scaling;
+	vstat.winheight = vstat.scrnheight * scaling;
+	aspect_fix(&vstat.winwidth, &vstat.winheight, vstat.aspect_width, vstat.aspect_height);
+	if (oldcols != vstat.cols) {
+		if (oldcols == 0) {
+			if (ciolib_initial_window_width > 0)
+				vstat.winwidth = ciolib_initial_window_width;
+			if (ciolib_initial_window_height > 0)
+				vstat.winheight = ciolib_initial_window_height;
+			if (vstat.cols == 40)
+				oldcols = 40;
+		}
+		if (oldcols == 40) {
+			vstat.winwidth /= 2;
+			vstat.winheight /= 2;
+		}
+		if (vstat.cols == 40) {
+			vstat.winwidth *= 2;
+			vstat.winheight *= 2;
+		}
+	}
+	if (vstat.winwidth < vstat.scrnwidth)
+		vstat.winwidth = vstat.scrnwidth;
+	if (vstat.winheight < vstat.scrnheight)
+		vstat.winheight = vstat.scrnheight;
+	pthread_mutex_unlock(&vstatlock);
+
+	return;
+}
+
+void
+gdi_setname(const char *name)
+{
+}
+
+void
+gdi_settitle(const char *title)
+{
+}
+
+void
+gdi_seticon(const void *icon, unsigned long size)
+{
+}
+
+void
+gdi_copytext(const char *text, size_t buflen)
+{
+}
+
+char *
+gdi_getcliptext(void)
+{
+	return NULL;
+}
+
+int
+gdi_get_window_info(int *width, int *height, int *xpos, int *ypos)
+{
+}
+
+int
+gdi_init(int mode)
+{
+	pthread_mutex_init(&gdi_headlock, NULL);
+	pthread_mutex_init(&bmp_lock, NULL);
+
+	bitmap_drv_init(gdi_drawrect, gdi_flush);
+	gdi_textmode(mode);
+
+	_beginthread(gdi_thread, 0, NULL);
+
+	cio_api.mode=CIOLIB_MODE_GDI;
+	FreeConsole();
+	cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
+	return(0);
+}
+
+int
+gdi_initciolib(int mode)
+{
+debug = fopen("gdi.log", "w");
+	pthread_mutex_init(&gdi_headlock, NULL);
+	pthread_mutex_init(&bmp_lock, NULL);
+
+	return(gdi_init(mode));
+}
+
+void
+gdi_drawrect(struct rectlist *data)
+{
+	data->next = NULL;
+	pthread_mutex_lock(&gdi_headlock);
+	if (update_list == NULL)
+		update_list = update_list_tail = data;
+	else {
+		update_list_tail->next = data;
+		update_list_tail = data;
+	}
+	pthread_mutex_unlock(&gdi_headlock);
+}
+
+void
+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;
+	update_list = update_list_tail = NULL;
+	pthread_mutex_unlock(&gdi_headlock);
+	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);
+			//pthread_mutex_lock(&vstatlock);
+			//StretchBlt(mDC2, 0, 0, vstat.winwidth, vstat.winheight, mDC1, 0, 0, vstat.scrnwidth, vstat.scrnheight, SRCCOPY);
+			//pthread_mutex_unlock(&vstatlock);
+			SelectObject(mDC1, obmp1);
+			SelectObject(mDC2, obmp2);
+			pthread_mutex_unlock(&bmp_lock);
+			DeleteObject(di);
+			DeleteDC(mDC2);
+			DeleteDC(mDC1);
+			InvalidateRect(win, NULL, FALSE);
+		}
+		bitmap_drv_free_rect(list);
+	}
+}
+
+void
+gdi_setscaling(int newval)
+{
+}
+
+int
+gdi_getscaling(void)
+{
+	return 1;
+}
+
+int
+gdi_mousepointer(enum ciolib_mouse_ptr type)
+{
+	return -1;// 0 on success
+}
+
+int
+gdi_showmouse(void)
+{
+	return 1;
+}
+
+int
+gdi_hidemouse(void)
+{
+	return 0;
+}
+
+void
+gdi_setwinposition(int x, int y)
+{
+}
+
+void
+gdi_setwinsize(int w, int h)
+{
+}
diff --git a/src/conio/win32gdi.h b/src/conio/win32gdi.h
new file mode 100644
index 0000000000000000000000000000000000000000..131b8298a4d2926f3529aecdf91308e54972ac86
--- /dev/null
+++ b/src/conio/win32gdi.h
@@ -0,0 +1,28 @@
+#ifndef WIN32GDI_H
+#define WIN32GDI_H
+
+#include "bitmap_con.h"
+
+int gdi_kbhit(void);
+int gdi_getch(void);
+void gdi_beep(void);
+void gdi_textmode(int mode);
+void gdi_setname(const char *name);
+void gdi_settitle(const char *title);
+void gdi_seticon(const void *icon, unsigned long size);
+void gdi_copytext(const char *text, size_t buflen);
+char * gdi_getcliptext(void);
+int gdi_get_window_info(int *width, int *height, int *xpos, int *ypos);
+int gdi_init(int mode);
+int gdi_initciolib(int mode);
+void gdi_drawrect(struct rectlist *data);
+void gdi_flush(void);
+void gdi_setscaling(int newval);
+int gdi_getscaling(void);
+int gdi_mousepointer(enum ciolib_mouse_ptr type);
+int gdi_showmouse(void);
+int gdi_hidemouse(void);
+void gdi_setwinposition(int x, int y);
+void gdi_setwinsize(int w, int h);
+
+#endif