1 #include <windows.h> 2 3 #undef Rectangle 4 #define Rectangle _Rectangle 5 6 #include "u.h" 7 #include "lib.h" 8 #include "kern/dat.h" 9 #include "kern/fns.h" 10 #include "error.h" 11 #include "user.h" 12 #include <draw.h> 13 #include <memdraw.h> 14 #include "screen.h" 15 #include "keyboard.h" 16 17 Memimage *gscreen; 18 Screeninfo screen; 19 20 extern int mousequeue; 21 static int depth; 22 23 static HINSTANCE inst; 24 static HWND window; 25 static HPALETTE palette; 26 static LOGPALETTE *logpal; 27 static Lock gdilock; 28 static BITMAPINFO *bmi; 29 static HCURSOR hcursor; 30 31 static void winproc(void *); 32 static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); 33 static void paletteinit(void); 34 static void bmiinit(void); 35 36 static int readybit; 37 static Rendez rend; 38 39 Point ZP; 40 41 static int 42 isready(void*a) 43 { 44 return readybit; 45 } 46 47 void 48 screeninit(void) 49 { 50 int fmt; 51 int dx, dy; 52 53 memimageinit(); 54 if(depth == 0) 55 depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL); 56 switch(depth){ 57 case 32: 58 screen.dibtype = DIB_RGB_COLORS; 59 screen.depth = 32; 60 fmt = XRGB32; 61 break; 62 case 24: 63 screen.dibtype = DIB_RGB_COLORS; 64 screen.depth = 24; 65 fmt = RGB24; 66 break; 67 case 16: 68 screen.dibtype = DIB_RGB_COLORS; 69 screen.depth = 16; 70 fmt = RGB15; /* [sic] */ 71 break; 72 case 8: 73 default: 74 screen.dibtype = DIB_PAL_COLORS; 75 screen.depth = 8; 76 depth = 8; 77 fmt = CMAP8; 78 break; 79 } 80 dx = GetDeviceCaps(GetDC(NULL), HORZRES); 81 dy = GetDeviceCaps(GetDC(NULL), VERTRES); 82 83 gscreen = allocmemimage(Rect(0,0,dx,dy), fmt); 84 kproc("winscreen", winproc, 0); 85 ksleep(&rend, isready, 0); 86 } 87 88 uchar* 89 attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X) 90 { 91 *r = gscreen->r; 92 *chan = gscreen->chan; 93 *depth = gscreen->depth; 94 *width = gscreen->width; 95 *softscreen = 1; 96 97 return gscreen->data->bdata; 98 } 99 100 void 101 flushmemscreen(Rectangle r) 102 { 103 screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP, 104 gscreen->width*sizeof(ulong)); 105 // Sleep(100); 106 } 107 108 void 109 screenload(Rectangle r, int depth, uchar *p, Point pt, int step) 110 { 111 int dx, dy, delx; 112 HDC hdc; 113 RECT winr; 114 115 if(depth != gscreen->depth) 116 panic("screenload: bad ldepth"); 117 118 /* 119 * Sometimes we do get rectangles that are off the 120 * screen to the negative axes, for example, when 121 * dragging around a window border in a Move operation. 122 */ 123 if(rectclip(&r, gscreen->r) == 0) 124 return; 125 126 if((step&3) != 0 || ((pt.x*depth)%32) != 0 || ((ulong)p&3) != 0) 127 panic("screenload: bad params %d %d %ux", step, pt.x, p); 128 dx = r.max.x - r.min.x; 129 dy = r.max.y - r.min.y; 130 131 if(dx <= 0 || dy <= 0) 132 return; 133 134 if(depth == 24) 135 delx = r.min.x % 4; 136 else 137 delx = r.min.x & (31/depth); 138 139 p += (r.min.y-pt.y)*step; 140 p += ((r.min.x-delx-pt.x)*depth)>>3; 141 142 if(GetWindowRect(window, &winr)==0) 143 return; 144 if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0) 145 return; 146 147 lock(&gdilock); 148 149 hdc = GetDC(window); 150 SelectPalette(hdc, palette, 0); 151 RealizePalette(hdc); 152 153 //FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH)); 154 //GdiFlush(); 155 //Sleep(100); 156 157 bmi->bmiHeader.biWidth = (step*8)/depth; 158 bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */ 159 160 StretchDIBits(hdc, r.min.x, r.min.y, dx, dy, 161 delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY); 162 163 ReleaseDC(window, hdc); 164 165 GdiFlush(); 166 167 unlock(&gdilock); 168 } 169 170 static void 171 winproc(void *a) 172 { 173 WNDCLASS wc; 174 MSG msg; 175 176 inst = GetModuleHandle(NULL); 177 178 paletteinit(); 179 bmiinit(); 180 terminit(); 181 182 wc.style = 0; 183 wc.lpfnWndProc = WindowProc; 184 wc.cbClsExtra = 0; 185 wc.cbWndExtra = 0; 186 wc.hInstance = inst; 187 wc.hIcon = LoadIcon(inst, NULL); 188 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 189 wc.hbrBackground = GetStockObject(WHITE_BRUSH); 190 wc.lpszMenuName = 0; 191 wc.lpszClassName = "9pmgraphics"; 192 RegisterClass(&wc); 193 194 window = CreateWindowEx( 195 0, /* extended style */ 196 "9pmgraphics", /* class */ 197 "drawterm screen", /* caption */ 198 WS_OVERLAPPEDWINDOW, /* style */ 199 CW_USEDEFAULT, /* init. x pos */ 200 CW_USEDEFAULT, /* init. y pos */ 201 CW_USEDEFAULT, /* init. x size */ 202 CW_USEDEFAULT, /* init. y size */ 203 NULL, /* parent window (actually owner window for overlapped)*/ 204 NULL, /* menu handle */ 205 inst, /* program handle */ 206 NULL /* create parms */ 207 ); 208 209 if(window == nil) 210 panic("can't make window\n"); 211 212 ShowWindow(window, SW_SHOWDEFAULT); 213 UpdateWindow(window); 214 215 readybit = 1; 216 wakeup(&rend); 217 218 screen.reshaped = 0; 219 220 while(GetMessage(&msg, NULL, 0, 0)) { 221 TranslateMessage(&msg); 222 DispatchMessage(&msg); 223 } 224 // MessageBox(0, "winproc", "exits", MB_OK); 225 ExitProcess(0); 226 } 227 228 int 229 col(int v, int n) 230 { 231 int i, c; 232 233 c = 0; 234 for(i = 0; i < 8; i += n) 235 c |= v << (16-(n+i)); 236 return c >> 8; 237 } 238 239 240 void 241 paletteinit(void) 242 { 243 PALETTEENTRY *pal; 244 int r, g, b, cr, cg, cb, v; 245 int num, den; 246 int i, j; 247 248 logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1); 249 if(logpal == nil) 250 panic("out of memory"); 251 logpal->palVersion = 0x300; 252 logpal->palNumEntries = 256; 253 pal = logpal->palPalEntry; 254 255 for(r=0,i=0; r<4; r++) { 256 for(v=0; v<4; v++,i+=16){ 257 for(g=0,j=v-r; g<4; g++) { 258 for(b=0; b<4; b++,j++){ 259 den=r; 260 if(g>den) 261 den=g; 262 if(b>den) 263 den=b; 264 /* divide check -- pick grey shades */ 265 if(den==0) 266 cr=cg=cb=v*17; 267 else{ 268 num=17*(4*den+v); 269 cr=r*num/den; 270 cg=g*num/den; 271 cb=b*num/den; 272 } 273 pal[i+(j&15)].peRed = cr; 274 pal[i+(j&15)].peGreen = cg; 275 pal[i+(j&15)].peBlue = cb; 276 pal[i+(j&15)].peFlags = 0; 277 } 278 } 279 } 280 } 281 palette = CreatePalette(logpal); 282 } 283 284 285 void 286 getcolor(ulong i, ulong *r, ulong *g, ulong *b) 287 { 288 PALETTEENTRY *pal; 289 290 pal = logpal->palPalEntry; 291 *r = pal[i].peRed; 292 *g = pal[i].peGreen; 293 *b = pal[i].peBlue; 294 } 295 296 void 297 bmiinit(void) 298 { 299 ushort *p; 300 int i; 301 302 bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1); 303 if(bmi == 0) 304 panic("out of memory"); 305 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 306 bmi->bmiHeader.biWidth = 0; 307 bmi->bmiHeader.biHeight = 0; /* - => origin upper left */ 308 bmi->bmiHeader.biPlanes = 1; 309 bmi->bmiHeader.biBitCount = depth; 310 bmi->bmiHeader.biCompression = BI_RGB; 311 bmi->bmiHeader.biSizeImage = 0; 312 bmi->bmiHeader.biXPelsPerMeter = 0; 313 bmi->bmiHeader.biYPelsPerMeter = 0; 314 bmi->bmiHeader.biClrUsed = 0; 315 bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */ 316 317 p = (ushort*)bmi->bmiColors; 318 for(i = 0; i < 256; i++) 319 p[i] = i; 320 } 321 322 LRESULT CALLBACK 323 WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 324 { 325 PAINTSTRUCT paint; 326 HDC hdc; 327 LONG x, y, b; 328 int i; 329 Rectangle r; 330 331 switch(msg) { 332 case WM_CREATE: 333 break; 334 case WM_SETCURSOR: 335 /* User set */ 336 if(hcursor != NULL) { 337 SetCursor(hcursor); 338 return 1; 339 } 340 return DefWindowProc(hwnd, msg, wparam, lparam); 341 case WM_MOUSEMOVE: 342 case WM_LBUTTONUP: 343 case WM_MBUTTONUP: 344 case WM_RBUTTONUP: 345 case WM_LBUTTONDOWN: 346 case WM_MBUTTONDOWN: 347 case WM_RBUTTONDOWN: 348 x = LOWORD(lparam); 349 y = HIWORD(lparam); 350 b = 0; 351 if(wparam & MK_LBUTTON) 352 b = 1; 353 if(wparam & MK_MBUTTON) 354 b |= 2; 355 if(wparam & MK_RBUTTON) { 356 if(wparam & MK_SHIFT) 357 b |= 2; 358 else 359 b |= 4; 360 } 361 lock(&mouse.lk); 362 i = mouse.wi; 363 if(mousequeue) { 364 if(i == mouse.ri || mouse.lastb != b || mouse.trans) { 365 mouse.wi = (i+1)%Mousequeue; 366 if(mouse.wi == mouse.ri) 367 mouse.ri = (mouse.ri+1)%Mousequeue; 368 mouse.trans = mouse.lastb != b; 369 } else { 370 i = (i-1+Mousequeue)%Mousequeue; 371 } 372 } else { 373 mouse.wi = (i+1)%Mousequeue; 374 mouse.ri = i; 375 } 376 mouse.queue[i].xy.x = x; 377 mouse.queue[i].xy.y = y; 378 mouse.queue[i].buttons = b; 379 mouse.queue[i].msec = ticks(); 380 mouse.lastb = b; 381 unlock(&mouse.lk); 382 wakeup(&mouse.r); 383 break; 384 385 case WM_CHAR: 386 /* repeat count is lparam & 0xf */ 387 switch(wparam){ 388 case '\n': 389 wparam = '\r'; 390 break; 391 case '\r': 392 wparam = '\n'; 393 break; 394 } 395 kbdputc(kbdq, wparam); 396 break; 397 398 case WM_SYSKEYUP: 399 break; 400 case WM_SYSKEYDOWN: 401 case WM_KEYDOWN: 402 switch(wparam) { 403 case VK_MENU: 404 kbdputc(kbdq, Kalt); 405 break; 406 case VK_INSERT: 407 kbdputc(kbdq, Kins); 408 break; 409 case VK_DELETE: 410 // kbdputc(kbdq, Kdel); 411 kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h 412 break; 413 case VK_UP: 414 kbdputc(kbdq, Kup); 415 break; 416 case VK_DOWN: 417 kbdputc(kbdq, Kdown); 418 break; 419 case VK_LEFT: 420 kbdputc(kbdq, Kleft); 421 break; 422 case VK_RIGHT: 423 kbdputc(kbdq, Kright); 424 break; 425 } 426 break; 427 428 case WM_CLOSE: 429 DestroyWindow(hwnd); 430 break; 431 432 case WM_DESTROY: 433 PostQuitMessage(0); 434 break; 435 436 case WM_PALETTECHANGED: 437 if((HWND)wparam == hwnd) 438 break; 439 /* fall through */ 440 case WM_QUERYNEWPALETTE: 441 hdc = GetDC(hwnd); 442 SelectPalette(hdc, palette, 0); 443 if(RealizePalette(hdc) != 0) 444 InvalidateRect(hwnd, nil, 0); 445 ReleaseDC(hwnd, hdc); 446 break; 447 448 case WM_PAINT: 449 hdc = BeginPaint(hwnd, &paint); 450 r.min.x = paint.rcPaint.left; 451 r.min.y = paint.rcPaint.top; 452 r.max.x = paint.rcPaint.right; 453 r.max.y = paint.rcPaint.bottom; 454 flushmemscreen(r); 455 EndPaint(hwnd, &paint); 456 break; 457 case WM_COMMAND: 458 case WM_SETFOCUS: 459 case WM_DEVMODECHANGE: 460 case WM_WININICHANGE: 461 case WM_INITMENU: 462 default: 463 return DefWindowProc(hwnd, msg, wparam, lparam); 464 } 465 return 0; 466 } 467 468 void 469 mouseset(Point xy) 470 { 471 POINT pt; 472 473 pt.x = xy.x; 474 pt.y = xy.y; 475 MapWindowPoints(window, 0, &pt, 1); 476 SetCursorPos(pt.x, pt.y); 477 } 478 479 void 480 setcursor(void) 481 { 482 HCURSOR nh; 483 int x, y, h, w; 484 uchar *sp, *cp; 485 uchar *and, *xor; 486 487 h = GetSystemMetrics(SM_CYCURSOR); 488 w = (GetSystemMetrics(SM_CXCURSOR)+7)/8; 489 490 and = mallocz(h*w, 1); 491 memset(and, 0xff, h*w); 492 xor = mallocz(h*w, 1); 493 494 lock(&cursor.lk); 495 for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) { 496 for(x=0; x<2; x++) { 497 and[y*w+x] = ~(*sp|*cp); 498 xor[y*w+x] = ~*sp & *cp; 499 cp++; 500 sp++; 501 } 502 } 503 nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y, 504 GetSystemMetrics(SM_CXCURSOR), h, 505 and, xor); 506 if(nh != NULL) { 507 SetCursor(nh); 508 if(hcursor != NULL) 509 DestroyCursor(hcursor); 510 hcursor = nh; 511 } 512 unlock(&cursor.lk); 513 514 free(and); 515 free(xor); 516 517 PostMessage(window, WM_SETCURSOR, (int)window, 0); 518 } 519 520 void 521 cursorarrow(void) 522 { 523 if(hcursor != 0) { 524 DestroyCursor(hcursor); 525 hcursor = 0; 526 } 527 SetCursor(LoadCursor(0, IDC_ARROW)); 528 PostMessage(window, WM_SETCURSOR, (int)window, 0); 529 } 530 531 532 void 533 setcolor(ulong index, ulong red, ulong green, ulong blue) 534 { 535 } 536 537 538 uchar* 539 clipreadunicode(HANDLE h) 540 { 541 Rune *p; 542 int n; 543 uchar *q; 544 545 p = GlobalLock(h); 546 n = wstrutflen(p)+1; 547 q = malloc(n); 548 wstrtoutf(q, p, n); 549 GlobalUnlock(h); 550 551 return q; 552 } 553 554 uchar * 555 clipreadutf(HANDLE h) 556 { 557 uchar *p; 558 559 p = GlobalLock(h); 560 p = strdup(p); 561 GlobalUnlock(h); 562 563 return p; 564 } 565 566 char* 567 clipread(void) 568 { 569 HANDLE h; 570 uchar *p; 571 572 if(!OpenClipboard(window)) { 573 oserror(); 574 return strdup(""); 575 } 576 577 if((h = GetClipboardData(CF_UNICODETEXT))) 578 p = clipreadunicode(h); 579 else if((h = GetClipboardData(CF_TEXT))) 580 p = clipreadutf(h); 581 else { 582 oserror(); 583 p = strdup(""); 584 } 585 586 CloseClipboard(); 587 return p; 588 } 589 590 int 591 clipwrite(char *buf) 592 { 593 HANDLE h; 594 char *p, *e; 595 Rune *rp; 596 int n = strlen(buf); 597 598 if(!OpenClipboard(window)) { 599 oserror(); 600 return -1; 601 } 602 603 if(!EmptyClipboard()) { 604 oserror(); 605 CloseClipboard(); 606 return -1; 607 } 608 609 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune)); 610 if(h == NULL) 611 panic("out of memory"); 612 rp = GlobalLock(h); 613 p = buf; 614 e = p+n; 615 while(p<e) 616 p += chartorune(rp++, p); 617 *rp = 0; 618 GlobalUnlock(h); 619 620 SetClipboardData(CF_UNICODETEXT, h); 621 622 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1); 623 if(h == NULL) 624 panic("out of memory"); 625 p = GlobalLock(h); 626 memcpy(p, buf, n); 627 p[n] = 0; 628 GlobalUnlock(h); 629 630 SetClipboardData(CF_TEXT, h); 631 632 CloseClipboard(); 633 return n; 634 } 635 636 int 637 atlocalconsole(void) 638 { 639 return 1; 640 } 641