1 #define Unknown WUnknown 2 #define Colormap WColormap 3 #define Cursor WCursor 4 #define Display WDisplay 5 #define Drawable WDrawable 6 #define Font WFont 7 #define GC WGC 8 #define Point WPoint 9 #define Rectangle WRectangle 10 #define Screen WScreen 11 #define Visual WVisual 12 #define Window WWindow 13 14 #include <windows.h> 15 16 #undef Colormap 17 #undef Cursor 18 #undef Display 19 #undef XDrawable 20 #undef Font 21 #undef GC 22 #undef Point 23 #undef Rectangle 24 #undef Screen 25 #undef Visual 26 #undef Window 27 #undef Unknown 28 29 #include "dat.h" 30 #include "fns.h" 31 #include "error.h" 32 #include <draw.h> 33 #include "keyboard.h" 34 #include "cursor.h" 35 #include "r16.h" 36 37 extern ulong displaychan; 38 39 extern int bytesperline(Rectangle, int); 40 extern int main(int argc, char **argv); 41 static void dprint(char*, ...); 42 static DWORD WINAPI winproc(LPVOID); 43 44 static HINSTANCE inst; 45 static HINSTANCE previnst; 46 static int cmdshow; 47 static HWND window; 48 static HDC screen; 49 static HPALETTE palette; 50 static int maxxsize; 51 static int maxysize; 52 static int attached; 53 static int isunicode = 1; 54 static HCURSOR hcursor; 55 56 char *argv0 = "inferno"; 57 static ulong *data; 58 59 extern DWORD PlatformId; 60 char* gkscanid = "emu_win32vk"; 61 62 int WINAPI 63 WinMain(HINSTANCE winst, HINSTANCE wprevinst, LPSTR cmdline, int wcmdshow) 64 { 65 inst = winst; 66 previnst = wprevinst; 67 cmdshow = wcmdshow; 68 69 /* cmdline passed into WinMain does not contain name of executable. 70 * The globals __argc and __argv to include this info - like UNIX 71 */ 72 main(__argc, __argv); 73 return 0; 74 } 75 76 static void 77 dprint(char *fmt, ...) 78 { 79 va_list arg; 80 char buf[128]; 81 82 va_start(arg, fmt); 83 vseprint(buf, buf+sizeof(buf), fmt, (LPSTR)arg); 84 va_end(arg); 85 OutputDebugString("inferno: "); 86 OutputDebugString(buf); 87 } 88 89 static void 90 graphicscmap(PALETTEENTRY *pal) 91 { 92 int r, g, b, cr, cg, cb, v, p; 93 int num, den; 94 int i, j; 95 for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){ 96 for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){ 97 den=r; 98 if(g>den) den=g; 99 if(b>den) den=b; 100 if(den==0) /* divide check -- pick grey shades */ 101 cr=cg=cb=v*17; 102 else{ 103 num=17*(4*den+v); 104 cr=r*num/den; 105 cg=g*num/den; 106 cb=b*num/den; 107 } 108 p = i+(j&15); 109 pal[p].peRed = cr*0x01010101; 110 pal[p].peGreen = cg*0x01010101; 111 pal[p].peBlue = cb*0x01010101; 112 pal[p].peFlags = 0; 113 } 114 } 115 } 116 117 static void 118 graphicsgmap(PALETTEENTRY *pal, int d) 119 { 120 int i, j, s, m, p; 121 122 s = 8-d; 123 m = 1; 124 while(--d >= 0) 125 m *= 2; 126 m = 255/(m-1); 127 for(i=0; i < 256; i++){ 128 j = (i>>s)*m; 129 p = 255-i; 130 pal[p].peRed = pal[p].peGreen = pal[p].peBlue = (255-j)*0x01010101; 131 pal[p].peFlags = 0; 132 } 133 } 134 135 static ulong 136 autochan(void) 137 { 138 HDC dc; 139 int bpp; 140 141 dc = GetDC(NULL); 142 if (dc == NULL) 143 return CMAP8; 144 145 bpp = GetDeviceCaps(dc, BITSPIXEL); 146 if (bpp < 15) 147 return CMAP8; 148 if (bpp < 24) 149 return RGB15; 150 if (bpp < 32) 151 return RGB24; 152 return XRGB32; 153 } 154 155 uchar* 156 attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen) 157 { 158 int i, k; 159 ulong c; 160 DWORD h; 161 RECT bs; 162 RGBQUAD *rgb; 163 HBITMAP bits; 164 BITMAPINFO *bmi; 165 LOGPALETTE *logpal; 166 PALETTEENTRY *pal; 167 int bsh, bsw, sx, sy; 168 169 if(attached) 170 goto Return; 171 172 /* Compute bodersizes */ 173 memset(&bs, 0, sizeof(bs)); 174 AdjustWindowRect(&bs, WS_OVERLAPPEDWINDOW, 0); 175 bsw = bs.right - bs.left; 176 bsh = bs.bottom - bs.top; 177 sx = GetSystemMetrics(SM_CXFULLSCREEN) - bsw; 178 Xsize -= Xsize % 4; /* Round down */ 179 if(Xsize > sx) 180 Xsize = sx; 181 sy = GetSystemMetrics(SM_CYFULLSCREEN) - bsh + 20; 182 if(Ysize > sy) 183 Ysize = sy; 184 185 logpal = malloc(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY)); 186 if(logpal == nil) 187 return nil; 188 logpal->palVersion = 0x300; 189 logpal->palNumEntries = 256; 190 pal = logpal->palPalEntry; 191 192 c = displaychan; 193 if(c == 0) 194 c = autochan(); 195 k = 8; 196 if(TYPE(c) == CGrey){ 197 graphicsgmap(pal, NBITS(c)); 198 c = GREY8; 199 }else{ 200 if(c == RGB15) 201 k = 16; 202 else if(c == RGB24) 203 k = 24; 204 else if(c == XRGB32) 205 k = 32; 206 else 207 c = CMAP8; 208 graphicscmap(pal); 209 } 210 211 palette = CreatePalette(logpal); 212 213 if(k == 8) 214 bmi = malloc(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)); 215 else 216 bmi = malloc(sizeof(BITMAPINFOHEADER)); 217 if(bmi == nil) 218 return nil; 219 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 220 bmi->bmiHeader.biWidth = Xsize; 221 bmi->bmiHeader.biHeight = -Ysize; /* - => origin upper left */ 222 bmi->bmiHeader.biPlanes = 1; /* always 1 */ 223 bmi->bmiHeader.biBitCount = k; 224 bmi->bmiHeader.biCompression = BI_RGB; 225 bmi->bmiHeader.biSizeImage = 0; /* Xsize*Ysize*(k/8) */ 226 bmi->bmiHeader.biXPelsPerMeter = 0; 227 bmi->bmiHeader.biYPelsPerMeter = 0; 228 bmi->bmiHeader.biClrUsed = 0; 229 bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */ 230 231 if(k == 8){ 232 rgb = bmi->bmiColors; 233 for(i = 0; i < 256; i++){ 234 rgb[i].rgbRed = pal[i].peRed; 235 rgb[i].rgbGreen = pal[i].peGreen; 236 rgb[i].rgbBlue = pal[i].peBlue; 237 } 238 } 239 240 screen = CreateCompatibleDC(NULL); 241 if(screen == nil){ 242 fprint(2, "screen dc nil\n"); 243 return nil; 244 } 245 246 if(SelectPalette(screen, palette, 1) == nil){ 247 fprint(2, "select pallete failed\n"); 248 } 249 i = RealizePalette(screen); 250 GdiFlush(); 251 bits = CreateDIBSection(screen, bmi, DIB_RGB_COLORS, &data, nil, 0); 252 if(bits == nil){ 253 fprint(2, "CreateDIBSection failed\n"); 254 return nil; 255 } 256 257 SelectObject(screen, bits); 258 GdiFlush(); 259 CreateThread(0, 16384, winproc, nil, 0, &h); 260 attached = 1; 261 262 Return: 263 r->min.x = 0; 264 r->min.y = 0; 265 r->max.x = Xsize; 266 r->max.y = Ysize; 267 displaychan = c; 268 *chan = c; 269 *d = k; 270 *width = (Xsize/4)*(k/8); 271 *softscreen = 1; 272 return (uchar*)data; 273 } 274 275 void 276 flushmemscreen(Rectangle r) 277 { 278 RECT wr; 279 280 if(r.max.x<=r.min.x || r.max.y<=r.min.y) 281 return; 282 wr.left = r.min.x; 283 wr.top = r.min.y; 284 wr.right = r.max.x; 285 wr.bottom = r.max.y; 286 InvalidateRect(window, &wr, 0); 287 } 288 289 static void 290 scancode(WPARAM wparam, LPARAM lparam, int keyup) 291 { 292 uchar buf[2]; 293 294 if(!(lparam & (1<<30))) { /* don't auto-repeat chars */ 295 buf[0] = wparam; 296 buf[1] = wparam >> 8; 297 if (keyup) 298 buf[1] |= 0x80; 299 qproduce(gkscanq, buf, sizeof buf); 300 } 301 } 302 303 LRESULT CALLBACK 304 WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 305 { 306 PAINTSTRUCT paint; 307 HDC hdc; 308 LPMINMAXINFO mmi; 309 LONG x, y, w, h, b; 310 HCURSOR dcurs; 311 POINT m; 312 313 switch(msg) { 314 case WM_SETCURSOR: 315 /* User set */ 316 if(hcursor != NULL) { 317 SetCursor(hcursor); 318 break; 319 } 320 /* Pick the default */ 321 dcurs = LoadCursor(NULL, IDC_ARROW); 322 SetCursor(dcurs); 323 break; 324 case WM_MOUSEWHEEL: 325 if((int)wparam>0) 326 b = 8; 327 else 328 b = 16; 329 m.x = LOWORD(lparam); 330 m.y = HIWORD(lparam); 331 ScreenToClient(hwnd, &m); 332 goto mok; 333 case WM_LBUTTONDBLCLK: 334 b = (1<<8) | 1; 335 goto process; 336 case WM_MBUTTONDBLCLK: 337 b = (1<<8) | 2; 338 goto process; 339 case WM_RBUTTONDBLCLK: 340 b = (1<<8) | 4; 341 goto process; 342 case WM_MOUSEMOVE: 343 case WM_LBUTTONUP: 344 case WM_MBUTTONUP: 345 case WM_RBUTTONUP: 346 case WM_LBUTTONDOWN: 347 case WM_MBUTTONDOWN: 348 case WM_RBUTTONDOWN: 349 b = 0; 350 process: 351 m.x = LOWORD(lparam); 352 m.y = HIWORD(lparam); 353 mok: 354 if(wparam & MK_LBUTTON) 355 b |= 1; 356 if(wparam & MK_MBUTTON) 357 b |= 2; 358 if(wparam & MK_RBUTTON) { 359 if(wparam & MK_CONTROL) 360 b |= 2; //simulate middle button 361 else 362 b |= 4; //right button 363 } 364 mousetrack(b, m.x, m.y, 0); 365 break; 366 case WM_SYSKEYDOWN: 367 if(gkscanq) 368 scancode(wparam, lparam, 0); 369 break; 370 case WM_SYSKEYUP: 371 if(gkscanq) 372 scancode(wparam, lparam, 1); 373 else if(wparam == VK_MENU) 374 gkbdputc(gkbdq, Latin); 375 break; 376 case WM_KEYDOWN: 377 if(gkscanq) { 378 scancode(wparam, lparam, 0); 379 break; 380 } 381 switch(wparam) { 382 default: 383 return 0; 384 case VK_HOME: 385 wparam = Home; 386 break; 387 case VK_END: 388 wparam = End; 389 break; 390 case VK_UP: 391 wparam = Up; 392 break; 393 case VK_DOWN: 394 wparam = Down; 395 break; 396 case VK_LEFT: 397 wparam = Left; 398 break; 399 case VK_RIGHT: 400 wparam = Right; 401 break; 402 case VK_PRIOR: /* VK_PAGE_UP */ 403 wparam = Pgup; 404 break; 405 case VK_NEXT: /* VK_PAGE_DOWN */ 406 wparam = Pgdown; 407 break; 408 case VK_PRINT: 409 wparam = Print; 410 break; 411 case VK_SCROLL: 412 wparam = Scroll; 413 break; 414 case VK_PAUSE: 415 wparam = Pause; 416 break; 417 case VK_INSERT: 418 wparam = Ins; 419 break; 420 case VK_DELETE: 421 wparam = Del; 422 break; 423 /* 424 case VK_TAB: 425 if(GetKeyState(VK_SHIFT)<0) 426 wparam = BackTab; 427 else 428 wparam = '\t'; 429 break; 430 */ 431 } 432 gkbdputc(gkbdq, wparam); 433 break; 434 case WM_KEYUP: 435 if(gkscanq) 436 scancode(wparam, lparam, 1); 437 break; 438 case WM_CHAR: 439 if(gkscanq) 440 break; 441 switch(wparam) { 442 case '\n': 443 wparam = '\r'; 444 break; 445 case '\r': 446 wparam = '\n'; 447 break; 448 case '\t': 449 if(GetKeyState(VK_SHIFT)<0) 450 wparam = BackTab; 451 else 452 wparam = '\t'; 453 break; 454 } 455 if(lparam & KF_ALTDOWN) 456 wparam = APP | (wparam & 0xFF); 457 gkbdputc(gkbdq, wparam); 458 break; 459 case WM_CLOSE: 460 DestroyWindow(hwnd); 461 break; 462 case WM_DESTROY: 463 PostQuitMessage(0); 464 cleanexit(0); 465 break; 466 case WM_PALETTECHANGED: 467 if((HWND)wparam == hwnd) 468 break; 469 /* fall through */ 470 case WM_QUERYNEWPALETTE: 471 hdc = GetDC(hwnd); 472 SelectPalette(hdc, palette, 0); 473 if(RealizePalette(hdc) != 0) 474 InvalidateRect(hwnd, nil, 0); 475 ReleaseDC(hwnd, hdc); 476 break; 477 case WM_PAINT: 478 hdc = BeginPaint(hwnd, &paint); 479 SelectPalette(hdc, palette, 0); 480 RealizePalette(hdc); 481 x = paint.rcPaint.left; 482 y = paint.rcPaint.top; 483 w = paint.rcPaint.right - x; 484 h = paint.rcPaint.bottom - y; 485 BitBlt(hdc, x, y, w, h, screen, x, y, SRCCOPY); 486 EndPaint(hwnd, &paint); 487 break; 488 case WM_GETMINMAXINFO: 489 mmi = (LPMINMAXINFO)lparam; 490 mmi->ptMaxSize.x = maxxsize; 491 mmi->ptMaxSize.y = maxysize; 492 mmi->ptMaxTrackSize.x = maxxsize; 493 mmi->ptMaxTrackSize.y = maxysize; 494 break; 495 case WM_SYSCHAR: 496 case WM_COMMAND: 497 case WM_CREATE: 498 case WM_SETFOCUS: 499 case WM_DEVMODECHANGE: 500 case WM_WININICHANGE: 501 case WM_INITMENU: 502 default: 503 if(isunicode) 504 return DefWindowProcW(hwnd, msg, wparam, lparam); 505 return DefWindowProcA(hwnd, msg, wparam, lparam); 506 } 507 return 0; 508 } 509 510 static DWORD WINAPI 511 winproc(LPVOID x) 512 { 513 MSG msg; 514 RECT size; 515 WNDCLASSW wc; 516 WNDCLASSA wca; 517 DWORD ws; 518 519 if(!previnst){ 520 wc.style = CS_DBLCLKS; 521 wc.lpfnWndProc = WindowProc; 522 wc.cbClsExtra = 0; 523 wc.cbWndExtra = 0; 524 wc.hInstance = inst; 525 wc.hIcon = LoadIcon(inst, MAKEINTRESOURCE(100)); 526 wc.hCursor = NULL; 527 wc.hbrBackground = GetStockObject(WHITE_BRUSH); 528 529 wc.lpszMenuName = 0; 530 wc.lpszClassName = L"inferno"; 531 532 if(RegisterClassW(&wc) == 0){ 533 wca.style = wc.style; 534 wca.lpfnWndProc = wc.lpfnWndProc; 535 wca.cbClsExtra = wc.cbClsExtra; 536 wca.cbWndExtra = wc.cbWndExtra; 537 wca.hInstance = wc.hInstance; 538 wca.hIcon = wc.hIcon; 539 wca.hCursor = wc.hCursor; 540 wca.hbrBackground = wc.hbrBackground; 541 542 wca.lpszMenuName = 0; 543 wca.lpszClassName = "inferno"; 544 isunicode = 0; 545 546 RegisterClassA(&wca); 547 } 548 } 549 550 size.left = 0; 551 size.top = 0; 552 size.right = Xsize; 553 size.bottom = Ysize; 554 555 ws = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX; 556 557 if(AdjustWindowRect(&size, ws, 0)) { 558 maxxsize = size.right - size.left; 559 maxysize = size.bottom - size.top; 560 }else{ 561 maxxsize = Xsize + 40; 562 maxysize = Ysize + 40; 563 } 564 565 if(isunicode) { 566 window = CreateWindowExW( 567 0, /* extended style */ 568 L"inferno", /* class */ 569 L"Inferno", /* caption */ 570 ws, /* style */ 571 CW_USEDEFAULT, /* init. x pos */ 572 CW_USEDEFAULT, /* init. y pos */ 573 maxxsize, /* init. x size */ 574 maxysize, /* init. y size */ 575 NULL, /* parent window (actually owner window for overlapped) */ 576 NULL, /* menu handle */ 577 inst, /* program handle */ 578 NULL /* create parms */ 579 ); 580 }else{ 581 window = CreateWindowExA( 582 0, /* extended style */ 583 "inferno", /* class */ 584 "Inferno", /* caption */ 585 ws, /* style */ 586 CW_USEDEFAULT, /* init. x pos */ 587 CW_USEDEFAULT, /* init. y pos */ 588 maxxsize, /* init. x size */ 589 maxysize, /* init. y size */ 590 NULL, /* parent window (actually owner window for overlapped) */ 591 NULL, /* menu handle */ 592 inst, /* program handle */ 593 NULL /* create parms */ 594 ); 595 } 596 597 if(window == nil){ 598 fprint(2, "can't make window\n"); 599 ExitThread(0); 600 } 601 602 SetForegroundWindow(window); 603 ShowWindow(window, cmdshow); 604 UpdateWindow(window); 605 // CloseWindow(window); 606 607 if(isunicode) { 608 while(GetMessageW(&msg, NULL, 0, 0)) { 609 TranslateMessage(&msg); 610 DispatchMessageW(&msg); 611 } 612 }else{ 613 while(GetMessageA(&msg, NULL, 0, 0)) { 614 TranslateMessage(&msg); 615 DispatchMessageA(&msg); 616 } 617 } 618 attached = 0; 619 ExitThread(msg.wParam); 620 return 0; 621 } 622 623 void 624 setpointer(int x, int y) 625 { 626 POINT pt; 627 628 pt.x = x; pt.y = y; 629 ClientToScreen(window, &pt); 630 SetCursorPos(pt.x, pt.y); 631 } 632 633 void 634 drawcursor(Drawcursor* c) 635 { 636 HCURSOR nh, oh; 637 Rectangle ir; 638 int i, h, j, bpl, ch, cw; 639 uchar *bs, *bc, *and, *xor, *cand, *cxor; 640 641 /* Set the default system cursor */ 642 if(c->data == nil) { 643 oh = hcursor; 644 hcursor = NULL; 645 if(oh != NULL) { 646 SendMessage(window, WM_SETCURSOR, (int)window, 0); 647 DestroyCursor(oh); 648 } 649 return; 650 } 651 652 ir.min.x = c->minx; 653 ir.min.y = c->miny; 654 ir.max.x = c->maxx; 655 ir.max.y = c->maxy; 656 bpl = bytesperline(ir, 1); 657 658 h = (c->maxy-c->miny)/2; 659 660 ch = GetSystemMetrics(SM_CYCURSOR); 661 cw = (GetSystemMetrics(SM_CXCURSOR)+7)/8; 662 663 i = ch*cw; 664 and = malloc(2*i); 665 if(and == nil) 666 return; 667 xor = and + i; 668 memset(and, 0xff, i); 669 memset(xor, 0, i); 670 671 cand = and; 672 cxor = xor; 673 bc = c->data; 674 bs = c->data + h*bpl; 675 676 for(i = 0; i < ch && i < h; i++) { 677 for(j = 0; j < cw && j < bpl; j++) { 678 cand[j] = ~(bs[j] | bc[j]); 679 cxor[j] = ~bs[j] & bc[j]; 680 } 681 cand += cw; 682 cxor += cw; 683 bs += bpl; 684 bc += bpl; 685 } 686 nh = CreateCursor(inst, -c->hotx, -c->hoty, 8*cw, ch, and, xor); 687 if(nh != NULL) { 688 oh = hcursor; 689 hcursor = nh; 690 SendMessage(window, WM_SETCURSOR, (int)window, 0); 691 if(oh != NULL) 692 DestroyCursor(oh); 693 }else{ 694 print("CreateCursor error %d\n", GetLastError()); 695 print("CXCURSOR=%d\n", GetSystemMetrics(SM_CXCURSOR)); 696 print("CYCURSOR=%d\n", GetSystemMetrics(SM_CYCURSOR)); 697 } 698 free(and); 699 } 700 701 /* 702 * thanks to drawterm for these 703 */ 704 705 static char* 706 clipreadunicode(HANDLE h) 707 { 708 Rune16 *p; 709 int n; 710 char *q; 711 712 p = GlobalLock(h); 713 n = rune16nlen(p, runes16len(p)+1); 714 q = malloc(n); 715 if(q != nil) 716 runes16toutf(q, p, n); 717 GlobalUnlock(h); 718 719 if(q == nil) 720 error(Enovmem); 721 return q; 722 } 723 724 static char * 725 clipreadutf(HANDLE h) 726 { 727 uchar *p; 728 729 p = GlobalLock(h); 730 p = strdup(p); 731 GlobalUnlock(h); 732 733 if(p == nil) 734 error(Enovmem); 735 return p; 736 } 737 738 char* 739 clipread(void) 740 { 741 HANDLE h; 742 char *p; 743 744 if(!OpenClipboard(window)) 745 return strdup(""); 746 747 if((h = GetClipboardData(CF_UNICODETEXT))) 748 p = clipreadunicode(h); 749 else if((h = GetClipboardData(CF_TEXT))) 750 p = clipreadutf(h); 751 else 752 p = strdup(""); 753 754 CloseClipboard(); 755 return p; 756 } 757 758 int 759 clipwrite(char *buf) 760 { 761 HANDLE h; 762 char *p; 763 Rune16 *rp; 764 int n; 765 766 n = 0; 767 if(buf != nil) 768 n = strlen(buf); 769 if(!OpenClipboard(window)) 770 return -1; 771 772 if(!EmptyClipboard()){ 773 CloseClipboard(); 774 return -1; 775 } 776 777 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune16)); 778 if(h == NULL) 779 error(Enovmem); 780 rp = GlobalLock(h); 781 utftorunes16(rp, buf, n+1); 782 GlobalUnlock(h); 783 784 SetClipboardData(CF_UNICODETEXT, h); 785 786 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1); 787 if(h == NULL) 788 error(Enovmem); 789 p = GlobalLock(h); 790 memmove(p, buf, n); 791 p[n] = 0; 792 GlobalUnlock(h); 793 794 SetClipboardData(CF_TEXT, h); 795 796 CloseClipboard(); 797 return n; 798 } 799