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