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); }