diff options
Diffstat (limited to 'emu/Nt/win.c')
| -rw-r--r-- | emu/Nt/win.c | 795 |
1 files changed, 795 insertions, 0 deletions
diff --git a/emu/Nt/win.c b/emu/Nt/win.c new file mode 100644 index 00000000..93c79c25 --- /dev/null +++ b/emu/Nt/win.c @@ -0,0 +1,795 @@ +#define Unknown WUnknown +#define Colormap WColormap +#define Cursor WCursor +#define Display WDisplay +#define Drawable WDrawable +#define Font WFont +#define GC WGC +#define Point WPoint +#define Rectangle WRectangle +#define Screen WScreen +#define Visual WVisual +#define Window WWindow + +#include <windows.h> + +#undef Colormap +#undef Cursor +#undef Display +#undef XDrawable +#undef Font +#undef GC +#undef Point +#undef Rectangle +#undef Screen +#undef Visual +#undef Window +#undef Unknown + +#include "dat.h" +#include "fns.h" +#include "error.h" +#include <draw.h> +#include "keyboard.h" +#include "cursor.h" + +extern ulong displaychan; + +extern char* runestoutf(char*, Rune*, int); +extern int bytesperline(Rectangle, int); +extern int main(int argc, char **argv); +static void dprint(char*, ...); +static DWORD WINAPI winproc(LPVOID); + +static HINSTANCE inst; +static HINSTANCE previnst; +static int cmdshow; +static HWND window; +static HDC screen; +static HPALETTE palette; +static int maxxsize; +static int maxysize; +static int attached; +static int isunicode = 1; +static HCURSOR hcursor; + +char *argv0 = "inferno"; +static ulong *data; + +extern DWORD PlatformId; +char* gkscanid = "emu_win32vk"; + +int WINAPI +WinMain(HINSTANCE winst, HINSTANCE wprevinst, LPSTR cmdline, int wcmdshow) +{ + inst = winst; + previnst = wprevinst; + cmdshow = wcmdshow; + + /* cmdline passed into WinMain does not contain name of executable. + * The globals __argc and __argv to include this info - like UNIX + */ + main(__argc, __argv); + return 0; +} + +static void +dprint(char *fmt, ...) +{ + va_list arg; + char buf[128]; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, (LPSTR)arg); + va_end(arg); + OutputDebugString("inferno: "); + OutputDebugString(buf); +} + +static void +graphicscmap(PALETTEENTRY *pal) +{ + int r, g, b, cr, cg, cb, v, p; + int num, den; + int i, j; + for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){ + for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){ + den=r; + if(g>den) den=g; + if(b>den) den=b; + if(den==0) /* divide check -- pick grey shades */ + cr=cg=cb=v*17; + else{ + num=17*(4*den+v); + cr=r*num/den; + cg=g*num/den; + cb=b*num/den; + } + p = i+(j&15); + pal[p].peRed = cr*0x01010101; + pal[p].peGreen = cg*0x01010101; + pal[p].peBlue = cb*0x01010101; + pal[p].peFlags = 0; + } + } +} + +static void +graphicsgmap(PALETTEENTRY *pal, int d) +{ + int i, j, s, m, p; + + s = 8-d; + m = 1; + while(--d >= 0) + m *= 2; + m = 255/(m-1); + for(i=0; i < 256; i++){ + j = (i>>s)*m; + p = 255-i; + pal[p].peRed = pal[p].peGreen = pal[p].peBlue = (255-j)*0x01010101; + pal[p].peFlags = 0; + } +} + +static ulong +autochan(void) +{ + HDC dc; + int bpp; + + dc = GetDC(NULL); + if (dc == NULL) + return CMAP8; + + bpp = GetDeviceCaps(dc, BITSPIXEL); + if (bpp < 15) + return CMAP8; + if (bpp < 24) + return RGB15; + if (bpp < 32) + return RGB24; + return XRGB32; +} + +uchar* +attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen) +{ + int i, k; + ulong c; + DWORD h; + RECT bs; + RGBQUAD *rgb; + HBITMAP bits; + BITMAPINFO *bmi; + LOGPALETTE *logpal; + PALETTEENTRY *pal; + int bsh, bsw, sx, sy; + + if(attached) + goto Return; + + /* Compute bodersizes */ + memset(&bs, 0, sizeof(bs)); + AdjustWindowRect(&bs, WS_OVERLAPPEDWINDOW, 0); + bsw = bs.right - bs.left; + bsh = bs.bottom - bs.top; + sx = GetSystemMetrics(SM_CXFULLSCREEN) - bsw; + Xsize -= Xsize % 4; /* Round down */ + if(Xsize > sx) + Xsize = sx; + sy = GetSystemMetrics(SM_CYFULLSCREEN) - bsh + 20; + if(Ysize > sy) + Ysize = sy; + + logpal = malloc(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY)); + if(logpal == nil) + return nil; + logpal->palVersion = 0x300; + logpal->palNumEntries = 256; + pal = logpal->palPalEntry; + + c = displaychan; + if(c == 0) + c = autochan(); + k = 8; + if(TYPE(c) == CGrey){ + graphicsgmap(pal, NBITS(c)); + c = GREY8; + }else{ + if(c == RGB15) + k = 16; + else if(c == RGB24) + k = 24; + else if(c == XRGB32) + k = 32; + else + c = CMAP8; + graphicscmap(pal); + } + + palette = CreatePalette(logpal); + + if(k == 8) + bmi = malloc(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)); + else + bmi = malloc(sizeof(BITMAPINFOHEADER)); + if(bmi == nil) + return nil; + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = Xsize; + bmi->bmiHeader.biHeight = -Ysize; /* - => origin upper left */ + bmi->bmiHeader.biPlanes = 1; /* always 1 */ + bmi->bmiHeader.biBitCount = k; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biSizeImage = 0; /* Xsize*Ysize*(k/8) */ + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */ + + if(k == 8){ + rgb = bmi->bmiColors; + for(i = 0; i < 256; i++){ + rgb[i].rgbRed = pal[i].peRed; + rgb[i].rgbGreen = pal[i].peGreen; + rgb[i].rgbBlue = pal[i].peBlue; + } + } + + screen = CreateCompatibleDC(NULL); + if(screen == nil){ + fprint(2, "screen dc nil\n"); + return nil; + } + + if(SelectPalette(screen, palette, 1) == nil){ + fprint(2, "select pallete failed\n"); + } + i = RealizePalette(screen); + GdiFlush(); + bits = CreateDIBSection(screen, bmi, DIB_RGB_COLORS, &data, nil, 0); + if(bits == nil){ + fprint(2, "CreateDIBSection failed\n"); + return nil; + } + + SelectObject(screen, bits); + GdiFlush(); + CreateThread(0, 16384, winproc, nil, 0, &h); + attached = 1; + + Return: + r->min.x = 0; + r->min.y = 0; + r->max.x = Xsize; + r->max.y = Ysize; + displaychan = c; + *chan = c; + *d = k; + *width = (Xsize/4)*(k/8); + *softscreen = 1; + return (uchar*)data; +} + +void +flushmemscreen(Rectangle r) +{ + RECT wr; + + if(r.max.x<=r.min.x || r.max.y<=r.min.y) + return; + wr.left = r.min.x; + wr.top = r.min.y; + wr.right = r.max.x; + wr.bottom = r.max.y; + InvalidateRect(window, &wr, 0); +} + +static void +scancode(WPARAM wparam, LPARAM lparam, int keyup) +{ + uchar buf[2]; + + if(!(lparam & (1<<30))) { /* don't auto-repeat chars */ + buf[0] = wparam; + buf[1] = wparam >> 8; + if (keyup) + buf[1] |= 0x80; + qproduce(gkscanq, buf, sizeof buf); + } +} + +LRESULT CALLBACK +WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + PAINTSTRUCT paint; + HDC hdc; + LPMINMAXINFO mmi; + LONG x, y, w, h, b; + HCURSOR dcurs; + + switch(msg) { + case WM_SETCURSOR: + /* User set */ + if(hcursor != NULL) { + SetCursor(hcursor); + break; + } + /* Pick the default */ + dcurs = LoadCursor(NULL, IDC_ARROW); + SetCursor(dcurs); + break; + case WM_LBUTTONDBLCLK: + b = (1<<8) | 1; + goto process; + case WM_MBUTTONDBLCLK: + b = (1<<8) | 2; + goto process; + case WM_RBUTTONDBLCLK: + b = (1<<8) | 4; + goto process; + case WM_MOUSEMOVE: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + b = 0; + process: + x = LOWORD(lparam); + y = HIWORD(lparam); + if(wparam & MK_LBUTTON) + b |= 1; + if(wparam & MK_MBUTTON) + b |= 2; + if(wparam & MK_RBUTTON) { + if(wparam & MK_CONTROL) + b |= 2; //simulate middle button + else + b |= 4; //right button + } + mousetrack(b, x, y, 0); + break; + case WM_SYSKEYDOWN: + if(gkscanq) + scancode(wparam, lparam, 0); + break; + case WM_SYSKEYUP: + if(gkscanq) + scancode(wparam, lparam, 1); + else if(wparam == VK_MENU) + gkbdputc(gkbdq, Latin); + break; + case WM_KEYDOWN: + if(gkscanq) { + scancode(wparam, lparam, 0); + break; + } + switch(wparam) { + default: + return 0; + case VK_HOME: + wparam = Home; + break; + case VK_END: + wparam = End; + break; + case VK_UP: + wparam = Up; + break; + case VK_DOWN: + wparam = Down; + break; + case VK_LEFT: + wparam = Left; + break; + case VK_RIGHT: + wparam = Right; + break; + case VK_PRIOR: /* VK_PAGE_UP */ + wparam = Pgup; + break; + case VK_NEXT: /* VK_PAGE_DOWN */ + wparam = Pgdown; + break; + case VK_PRINT: + wparam = Print; + break; + case VK_SCROLL: + wparam = Scroll; + break; + case VK_PAUSE: + wparam = Pause; + break; + case VK_INSERT: + wparam = Ins; + break; + case VK_DELETE: + wparam = Del; + break; +/* + case VK_TAB: + if(GetKeyState(VK_SHIFT)<0) + wparam = BackTab; + else + wparam = '\t'; + break; +*/ + } + gkbdputc(gkbdq, wparam); + break; + case WM_KEYUP: + if(gkscanq) + scancode(wparam, lparam, 1); + break; + case WM_CHAR: + if(gkscanq) + break; + switch(wparam) { + case '\n': + wparam = '\r'; + break; + case '\r': + wparam = '\n'; + break; + case '\t': + if(GetKeyState(VK_SHIFT)<0) + wparam = BackTab; + else + wparam = '\t'; + break; + } + if(lparam & KF_ALTDOWN) + wparam = APP | (wparam & 0xFF); + gkbdputc(gkbdq, wparam); + break; + case WM_CLOSE: + // no longer used? + //m.b = 128; + //m.modify = 1; + //mousetrack(128, 0, 0, 1); + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + cleanexit(0); + break; + case WM_PALETTECHANGED: + if((HWND)wparam == hwnd) + break; + /* fall through */ + case WM_QUERYNEWPALETTE: + hdc = GetDC(hwnd); + SelectPalette(hdc, palette, 0); + if(RealizePalette(hdc) != 0) + InvalidateRect(hwnd, nil, 0); + ReleaseDC(hwnd, hdc); + break; + case WM_PAINT: + hdc = BeginPaint(hwnd, &paint); + SelectPalette(hdc, palette, 0); + RealizePalette(hdc); + x = paint.rcPaint.left; + y = paint.rcPaint.top; + w = paint.rcPaint.right - x; + h = paint.rcPaint.bottom - y; + BitBlt(hdc, x, y, w, h, screen, x, y, SRCCOPY); + EndPaint(hwnd, &paint); + break; + case WM_GETMINMAXINFO: + mmi = (LPMINMAXINFO)lparam; + mmi->ptMaxSize.x = maxxsize; + mmi->ptMaxSize.y = maxysize; + mmi->ptMaxTrackSize.x = maxxsize; + mmi->ptMaxTrackSize.y = maxysize; + break; + case WM_SYSCHAR: + case WM_COMMAND: + case WM_CREATE: + case WM_SETFOCUS: + case WM_DEVMODECHANGE: + case WM_WININICHANGE: + case WM_INITMENU: + default: + if(isunicode) + return DefWindowProcW(hwnd, msg, wparam, lparam); + return DefWindowProcA(hwnd, msg, wparam, lparam); + } + return 0; +} + +static DWORD WINAPI +winproc(LPVOID x) +{ + MSG msg; + RECT size; + WNDCLASSW wc; + WNDCLASSA wca; + DWORD ws; + + if(!previnst){ + wc.style = CS_DBLCLKS; + wc.lpfnWndProc = WindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = inst; + wc.hIcon = LoadIcon(inst, MAKEINTRESOURCE(100)); + wc.hCursor = NULL; + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + + wc.lpszMenuName = 0; + wc.lpszClassName = L"inferno"; + + if(RegisterClassW(&wc) == 0){ + wca.style = wc.style; + wca.lpfnWndProc = wc.lpfnWndProc; + wca.cbClsExtra = wc.cbClsExtra; + wca.cbWndExtra = wc.cbWndExtra; + wca.hInstance = wc.hInstance; + wca.hIcon = wc.hIcon; + wca.hCursor = wc.hCursor; + wca.hbrBackground = wc.hbrBackground; + + wca.lpszMenuName = 0; + wca.lpszClassName = "inferno"; + isunicode = 0; + + RegisterClassA(&wca); + } + } + + size.left = 0; + size.top = 0; + size.right = Xsize; + size.bottom = Ysize; + + ws = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX; + + if(AdjustWindowRect(&size, ws, 0)) { + maxxsize = size.right - size.left; + maxysize = size.bottom - size.top; + }else{ + maxxsize = Xsize + 40; + maxysize = Ysize + 40; + } + + if(isunicode) { + window = CreateWindowExW( + 0, /* extended style */ + L"inferno", /* class */ + L"Inferno", /* caption */ + ws, /* style */ + CW_USEDEFAULT, /* init. x pos */ + CW_USEDEFAULT, /* init. y pos */ + maxxsize, /* init. x size */ + maxysize, /* init. y size */ + NULL, /* parent window (actually owner window for overlapped) */ + NULL, /* menu handle */ + inst, /* program handle */ + NULL /* create parms */ + ); + }else{ + window = CreateWindowExA( + 0, /* extended style */ + "inferno", /* class */ + "Inferno", /* caption */ + ws, /* style */ + CW_USEDEFAULT, /* init. x pos */ + CW_USEDEFAULT, /* init. y pos */ + maxxsize, /* init. x size */ + maxysize, /* init. y size */ + NULL, /* parent window (actually owner window for overlapped) */ + NULL, /* menu handle */ + inst, /* program handle */ + NULL /* create parms */ + ); + } + + if(window == nil){ + fprint(2, "can't make window\n"); + ExitThread(0); + } + + SetForegroundWindow(window); + ShowWindow(window, cmdshow); + UpdateWindow(window); + // CloseWindow(window); + + if(isunicode) { + while(GetMessageW(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + }else{ + while(GetMessageA(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } + attached = 0; + ExitThread(msg.wParam); + return 0; +} + +void +setpointer(int x, int y) +{ + POINT pt; + + pt.x = x; pt.y = y; + ClientToScreen(window, &pt); + SetCursorPos(pt.x, pt.y); +} + +void +drawcursor(Drawcursor* c) +{ + HCURSOR nh, oh; + Rectangle ir; + int i, h, j, bpl, ch, cw; + uchar *bs, *bc, *and, *xor, *cand, *cxor; + + /* Set the default system cursor */ + if(c->data == nil) { + oh = hcursor; + hcursor = NULL; + if(oh != NULL) { + SendMessage(window, WM_SETCURSOR, (int)window, 0); + DestroyCursor(oh); + } + return; + } + + ir.min.x = c->minx; + ir.min.y = c->miny; + ir.max.x = c->maxx; + ir.max.y = c->maxy; + bpl = bytesperline(ir, 1); + + h = (c->maxy-c->miny)/2; + + ch = GetSystemMetrics(SM_CYCURSOR); + cw = (GetSystemMetrics(SM_CXCURSOR)+7)/8; + + i = ch*cw; + and = malloc(2*i); + if(and == nil) + return; + xor = and + i; + memset(and, 0xff, i); + memset(xor, 0, i); + + cand = and; + cxor = xor; + bc = c->data; + bs = c->data + h*bpl; + + for(i = 0; i < ch && i < h; i++) { + for(j = 0; j < cw && j < bpl; j++) { + cand[j] = ~(bs[j] | bc[j]); + cxor[j] = ~bs[j] & bc[j]; + } + cand += cw; + cxor += cw; + bs += bpl; + bc += bpl; + } + nh = CreateCursor(inst, -c->hotx, -c->hoty, 8*cw, ch, and, xor); + if(nh != NULL) { + oh = hcursor; + hcursor = nh; + SendMessage(window, WM_SETCURSOR, (int)window, 0); + if(oh != NULL) + DestroyCursor(oh); + }else{ + print("CreateCursor error %d\n", GetLastError()); + print("CXCURSOR=%d\n", GetSystemMetrics(SM_CXCURSOR)); + print("CYCURSOR=%d\n", GetSystemMetrics(SM_CYCURSOR)); + } + free(and); +} + +/* + * thanks to drawterm for these + */ + +static char* +clipreadunicode(HANDLE h) +{ + Rune *p; + int n; + char *q; + + p = GlobalLock(h); + n = runenlen(p, runestrlen(p)+1); + q = malloc(n); + if(q != nil) + runestoutf(q, p, n); + GlobalUnlock(h); + + if(q == nil) + error(Enovmem); + return q; +} + +static char * +clipreadutf(HANDLE h) +{ + uchar *p; + + p = GlobalLock(h); + p = strdup(p); + GlobalUnlock(h); + + if(p == nil) + error(Enovmem); + return p; +} + +char* +clipread(void) +{ + HANDLE h; + char *p; + + if(!OpenClipboard(window)) + return strdup(""); + + if((h = GetClipboardData(CF_UNICODETEXT))) + p = clipreadunicode(h); + else if((h = GetClipboardData(CF_TEXT))) + p = clipreadutf(h); + else + p = strdup(""); + + CloseClipboard(); + return p; +} + +int +clipwrite(char *buf) +{ + HANDLE h; + char *p, *e; + Rune *rp; + int n; + + n = 0; + if(buf != nil) + n = strlen(buf); + if(!OpenClipboard(window)) + return -1; + + if(!EmptyClipboard()){ + CloseClipboard(); + return -1; + } + + h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune)); + if(h == NULL) + error(Enovmem); + rp = GlobalLock(h); + p = buf; + e = p+n; + while(p<e) + p += chartorune(rp++, p); + *rp = 0; + GlobalUnlock(h); + + SetClipboardData(CF_UNICODETEXT, h); + + h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1); + if(h == NULL) + error(Enovmem); + p = GlobalLock(h); + memmove(p, buf, n); + p[n] = 0; + GlobalUnlock(h); + + SetClipboardData(CF_TEXT, h); + + CloseClipboard(); + return n; +} |
