ref: caef73363f896a1405ce6b9b6435f91e47a9b188
dir: /emu/Nt/win.c/
#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" #include "r16.h" extern ulong displaychan; 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; POINT m; 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_MOUSEWHEEL: if((int)wparam>0) b = 8; else b = 16; m.x = LOWORD(lparam); m.y = HIWORD(lparam); ScreenToClient(hwnd, &m); goto mok; 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: m.x = LOWORD(lparam); m.y = HIWORD(lparam); mok: 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, m.x, m.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: 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) { Rune16 *p; int n; char *q; p = GlobalLock(h); n = rune16nlen(p, runes16len(p)+1); q = malloc(n); if(q != nil) runes16toutf(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; Rune16 *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(Rune16)); if(h == NULL) error(Enovmem); rp = GlobalLock(h); utftorunes16(rp, buf, n+1); 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; }