xref: /plan9/sys/src/cmd/vnc/screen.c (revision f8e525ac91e3a7fae3f104837a69862dc348aa81)
1 #include	<u.h>
2 #include	<libc.h>
3 #include	"compat.h"
4 #include	"kbd.h"
5 #include	"error.h"
6 
7 #define	Image	IMAGE
8 #include	<draw.h>
9 #include	<memdraw.h>
10 #include	<cursor.h>
11 #include	"screen.h"
12 
13 enum
14 {
15 	CURSORDIM = 16
16 };
17 
18 Memimage	*gscreen;
19 Point		ZP;
20 int		cursorver;
21 Point		cursorpos;
22 
23 static Memimage		*back;
24 static Memimage		*conscol;
25 static Memimage		*curscol;
26 static Point		curpos;
27 static Memsubfont	*memdefont;
28 static Rectangle	flushr;
29 static Rectangle	window;
30 static int		h;
31 static int		w;
32 
33 static Rectangle	cursorr;
34 static Point		offscreen;
35 static uchar		cursset[CURSORDIM*CURSORDIM/8];
36 static uchar		cursclr[CURSORDIM*CURSORDIM/8];
37 static int		cursdrawvers = -1;
38 static Memimage		*cursorset;
39 static Memimage		*cursorclear;
40 static Cursor		screencursor;
41 
42 Cursor	arrow = {
43 	{ -1, -1 },
44 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
45 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
46 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
47 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
48 	},
49 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
50 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
51 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
52 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
53 	},
54 };
55 
56 void
screeninit(int x,int y,char * chanstr)57 screeninit(int x, int y, char *chanstr)
58 {
59 	Point p, q;
60 	char *greet;
61 	char buf[128];
62 	Memimage *grey;
63 	Rectangle r;
64 	int chan;
65 
66 	cursorver = 0;
67 
68 	memimageinit();
69 	chan = strtochan(chanstr);
70 	if(chan == 0)
71 		error("bad screen channel string");
72 
73 	r = Rect(0, 0, x, y);
74 	gscreen = allocmemimage(r, chan);
75 	if(gscreen == nil){
76 		snprint(buf, sizeof buf, "can't allocate screen image: %r");
77 		error(buf);
78 	}
79 
80 	offscreen = Pt(x + 100, y + 100);
81 	cursorr = Rect(0, 0, CURSORDIM, CURSORDIM);
82 	cursorset = allocmemimage(cursorr, GREY8);
83 	cursorclear = allocmemimage(cursorr, GREY1);
84 	if(cursorset == nil || cursorclear == nil){
85 		freememimage(gscreen);
86 		freememimage(cursorset);
87 		freememimage(cursorclear);
88 		gscreen = nil;
89 		cursorset = nil;
90 		cursorclear = nil;
91 		snprint(buf, sizeof buf, "can't allocate cursor images: %r");
92 		error(buf);
93 	}
94 
95 	drawlock();
96 
97 	/*
98 	 * set up goo for screenputs
99 	 */
100 	memdefont = getmemdefont();
101 
102 	back = memwhite;
103 	conscol = memblack;
104 
105 	/* a lot of work to get a grey color */
106 	curscol = allocmemimage(Rect(0,0,1,1), RGBA32);
107 	curscol->flags |= Frepl;
108 	curscol->clipr = gscreen->r;
109 	memfillcolor(curscol, 0xff0000ff);
110 
111 	memfillcolor(gscreen, 0x444488FF);
112 
113 	w = memdefont->info[' '].width;
114 	h = memdefont->height;
115 
116 	window.min = addpt(gscreen->r.min, Pt(20,20));
117 	window.max.x = window.min.x + Dx(gscreen->r)*3/4-40;
118 	window.max.y = window.min.y + Dy(gscreen->r)*3/4-100;
119 
120 	memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
121 	window = insetrect(window, 4);
122 	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
123 
124 	/* a lot of work to get a grey color */
125 	grey = allocmemimage(Rect(0,0,1,1), CMAP8);
126 	grey->flags |= Frepl;
127 	grey->clipr = gscreen->r;
128 	memfillcolor(grey, 0xAAAAAAFF);
129 	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
130 			window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S);
131 	freememimage(grey);
132 	window = insetrect(window, 5);
133 
134 	greet = " Plan 9 Console ";
135 	p = addpt(window.min, Pt(10, 0));
136 	q = memsubfontwidth(memdefont, greet);
137 	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
138 	window.min.y += h+6;
139 	curpos = window.min;
140 	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
141 	flushmemscreen(gscreen->r);
142 
143 	drawunlock();
144 
145 	setcursor(&arrow);
146 }
147 
148 uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)149 attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
150 {
151 	*r = gscreen->r;
152 	*d = gscreen->depth;
153 	*chan = gscreen->chan;
154 	*width = gscreen->width;
155 	*softscreen = 1;
156 
157 	return gscreen->data->bdata;
158 }
159 
160 void
getcolor(ulong,ulong * pr,ulong * pg,ulong * pb)161 getcolor(ulong , ulong* pr, ulong* pg, ulong* pb)
162 {
163 	*pr = 0;
164 	*pg = 0;
165 	*pb = 0;
166 }
167 
168 int
setcolor(ulong,ulong,ulong,ulong)169 setcolor(ulong , ulong , ulong , ulong )
170 {
171 	return 0;
172 }
173 
174 /*
175  * called with cursor unlocked, drawlock locked
176  */
177 void
cursordraw(Memimage * dst,Rectangle r)178 cursordraw(Memimage *dst, Rectangle r)
179 {
180 	static uchar set[CURSORDIM*CURSORDIM], clr[CURSORDIM*CURSORDIM/8];
181 	static int ver = -1;
182 	int i, j, n;
183 
184 	lock(&cursor);
185 	if(ver != cursorver){
186 		n = 0;
187 		for(i = 0; i < CURSORDIM*CURSORDIM/8; i += CURSORDIM/8){
188 			for(j = 0; j < CURSORDIM; j++){
189 				if(cursset[i + (j >> 3)] & (1 << (7 - (j & 7))))
190 					set[n] = 0xaa;
191 				else
192 					set[n] = 0;
193 				n++;
194 			}
195 		}
196 		memmove(clr, cursclr, CURSORDIM*CURSORDIM/8);
197 		ver = cursorver;
198 		unlock(&cursor);
199 		loadmemimage(cursorset, cursorr, set, CURSORDIM*CURSORDIM);
200 		loadmemimage(cursorclear, cursorr, clr, CURSORDIM*CURSORDIM/8);
201 	}else
202 		unlock(&cursor);
203 	memimagedraw(dst, r, memwhite, ZP, cursorclear, ZP, SoverD);
204 	memimagedraw(dst, r, curscol, ZP, cursorset, ZP, SoverD);
205 }
206 
207 /*
208  * called with cursor locked, drawlock possibly unlocked
209  */
210 Rectangle
cursorrect(void)211 cursorrect(void)
212 {
213 	Rectangle r;
214 
215 	r.min.x = cursorpos.x + cursor.offset.x;
216 	r.min.y = cursorpos.y + cursor.offset.y;
217 	r.max.x = r.min.x + CURSORDIM;
218 	r.max.y = r.min.y + CURSORDIM;
219 	return r;
220 }
221 
222 /*
223  * called with cursor locked, drawlock possibly unlocked
224  */
225 void
setcursor(Cursor * curs)226 setcursor(Cursor* curs)
227 {
228 	cursorver++;
229 	memmove(cursset, curs->set, CURSORDIM*CURSORDIM/8);
230 	memmove(cursclr, curs->clr, CURSORDIM*CURSORDIM/8);
231 }
232 
233 int
cursoron(int dolock)234 cursoron(int dolock)
235 {
236 	if(dolock)
237 		lock(&cursor);
238 	cursorpos = mousexy();
239 	if(dolock)
240 		unlock(&cursor);
241 
242 	return 0;
243 }
244 
245 void
cursoroff(int dolock)246 cursoroff(int dolock)
247 {
248 	if(dolock)
249 		lock(&cursor);
250 	cursorpos = offscreen;
251 	if(dolock)
252 		unlock(&cursor);
253 }
254 
255 void
blankscreen(int blank)256 blankscreen(int blank)
257 {
258 	USED(blank);
259 }
260 
261 static void
screenflush(void)262 screenflush(void)
263 {
264 	flushmemscreen(flushr);
265 	flushr = Rect(10000, 10000, -10000, -10000);
266 }
267 
268 static void
addflush(Rectangle r)269 addflush(Rectangle r)
270 {
271 	if(flushr.min.x >= flushr.max.x)
272 		flushr = r;
273 	else
274 		combinerect(&flushr, r);
275 }
276 
277 static void
scroll(void)278 scroll(void)
279 {
280 	int o;
281 	Point p;
282 	Rectangle r;
283 
284 	o = 8*h;
285 	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
286 	p = Pt(window.min.x, window.min.y+o);
287 	memimagedraw(gscreen, r, gscreen, p, nil, p, S);
288 	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
289 	memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
290 	flushmemscreen(gscreen->r);
291 
292 	curpos.y -= o;
293 }
294 
295 static void
screenputc(char * buf)296 screenputc(char *buf)
297 {
298 	Point p;
299 	int w, pos;
300 	Rectangle r;
301 	static int *xp;
302 	static int xbuf[256];
303 
304 	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
305 		xp = xbuf;
306 
307 	switch(buf[0]){
308 	case '\n':
309 		if(curpos.y+h >= window.max.y)
310 			scroll();
311 		curpos.y += h;
312 		screenputc("\r");
313 		break;
314 	case '\r':
315 		xp = xbuf;
316 		curpos.x = window.min.x;
317 		break;
318 	case '\t':
319 		p = memsubfontwidth(memdefont, " ");
320 		w = p.x;
321 		*xp++ = curpos.x;
322 		pos = (curpos.x-window.min.x)/w;
323 		pos = 8-(pos%8);
324 		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
325 		memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
326 		addflush(r);
327 		curpos.x += pos*w;
328 		break;
329 	case '\b':
330 		if(xp <= xbuf)
331 			break;
332 		xp--;
333 		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
334 		memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
335 		addflush(r);
336 		curpos.x = *xp;
337 		break;
338 	default:
339 		p = memsubfontwidth(memdefont, buf);
340 		w = p.x;
341 
342 		if(curpos.x >= window.max.x-w)
343 			screenputc("\n");
344 
345 		*xp++ = curpos.x;
346 		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
347 		memimagedraw(gscreen, r, back, back->r.min, memopaque, ZP, S);
348 		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
349 		addflush(r);
350 		curpos.x += w;
351 	}
352 }
353 
354 void
screenputs(char * s,int n)355 screenputs(char *s, int n)
356 {
357 	int i;
358 	Rune r;
359 	char buf[4];
360 
361 	drawlock();
362 	while(n > 0){
363 		i = chartorune(&r, s);
364 		if(i == 0){
365 			s++;
366 			--n;
367 			continue;
368 		}
369 		memmove(buf, s, i);
370 		buf[i] = 0;
371 		n -= i;
372 		s += i;
373 		screenputc(buf);
374 	}
375 	screenflush();
376 	drawunlock();
377 }
378