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