summaryrefslogtreecommitdiff
path: root/emu/Nt/win.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2009-03-25 15:55:14 +0000
committerCharles.Forsyth <devnull@localhost>2009-03-25 15:55:14 +0000
commitdfd1934d5e1ddbeb326f77fc0e52307c801a1a3e (patch)
treef1e8b23278caae95e01d88b00421d6c3642357ef /emu/Nt/win.c
parent78dfdcbd59dc8f36975e7695933e3f753957474c (diff)
x20090325-1554
Diffstat (limited to 'emu/Nt/win.c')
-rw-r--r--emu/Nt/win.c795
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;
+}