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