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
isready(void * a)43 isready(void*a)
44 {
45 return readybit;
46 }
47
48 void
screeninit(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*
attachscreen(Rectangle * r,ulong * chan,int * depth,int * width,int * softscreen,void ** X)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
flushmemscreen(Rectangle r)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
screenload(Rectangle r,int depth,uchar * p,Point pt,int step)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
winproc(void * a)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
col(int v,int n)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
paletteinit(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
getcolor(ulong i,ulong * r,ulong * g,ulong * b)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
bmiinit(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
WindowProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)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
mouseset(Point xy)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
setcursor(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
cursorarrow(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
setcolor(ulong index,ulong red,ulong green,ulong blue)539 setcolor(ulong index, ulong red, ulong green, ulong blue)
540 {
541 }
542
543
544 uchar*
clipreadunicode(HANDLE h)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 *
clipreadutf(HANDLE h)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*
clipread(void)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
clipwrite(char * buf)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
atlocalconsole(void)643 atlocalconsole(void)
644 {
645 return 1;
646 }
647