Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "vnc.h"
2
#include "vncv.h"
3
 
4
static struct {
5
	char	*name;
6
	int	num;
7
} enctab[] = {
8
	"copyrect",	EncCopyRect,
9
	"corre",	EncCorre,
10
	"hextile",	EncHextile,
11
	"raw",		EncRaw,
12
	"rre",		EncRre,
13
	"mousewarp",	EncMouseWarp,
14
};
15
 
16
static	uchar	*pixbuf;
17
static	uchar	*linebuf;
18
static	int	vpixb;
19
static	int	pixb;
20
static	void	(*pixcp)(uchar*, uchar*);
21
 
22
static void
23
vncrdcolor(Vnc *v, uchar *color)
24
{
25
	vncrdbytes(v, color, vpixb);
26
 
27
	if(cvtpixels)
28
		(*cvtpixels)(color, color, 1);
29
}
30
 
31
void
32
sendencodings(Vnc *v)
33
{
34
	char *f[10];
35
	int enc[10], nenc, i, j, nf;
36
 
37
	nf = tokenize(encodings, f, nelem(f));
38
	nenc = 0;
39
	for(i=0; i<nf; i++){
40
		for(j=0; j<nelem(enctab); j++)
41
			if(strcmp(f[i], enctab[j].name) == 0)
42
				break;
43
		if(j == nelem(enctab)){
44
			print("warning: unknown encoding %s\n", f[i]);
45
			continue;
46
		}
47
		enc[nenc++] = enctab[j].num;
48
	}
49
 
50
	vnclock(v);
51
	vncwrchar(v, MSetEnc);
52
	vncwrchar(v, 0);
53
	vncwrshort(v, nenc);
54
	for(i=0; i<nenc; i++)
55
		vncwrlong(v, enc[i]);
56
	vncflush(v);
57
	vncunlock(v);
58
}
59
 
60
void
61
requestupdate(Vnc *v, int incremental)
62
{
63
	int x, y;
64
 
65
	lockdisplay(display);
66
	x = Dx(screen->r);
67
	y = Dy(screen->r);
68
	unlockdisplay(display);
69
	if(x > v->dim.x)
70
		x = v->dim.x;
71
	if(y > v->dim.y)
72
		y = v->dim.y;
73
	vnclock(v);
74
	vncwrchar(v, MFrameReq);
75
	vncwrchar(v, incremental);
76
	vncwrrect(v, Rpt(ZP, Pt(x, y)));
77
	vncflush(v);
78
	vncunlock(v);
79
}
80
 
81
static Rectangle
82
clippixbuf(Rectangle r, int maxx, int maxy)
83
{
84
	int y, h, stride1, stride2;
85
 
86
	if(r.min.x > maxx || r.min.y > maxy){
87
		r.max.x = 0;
88
		return r;
89
	}
90
	if(r.max.y > maxy)
91
		r.max.y = maxy;
92
	if(r.max.x <= maxx)
93
		return r;
94
 
95
	stride2 = Dx(r) * pixb;
96
	r.max.x = maxx;
97
	stride1 = Dx(r) * pixb;
98
	h = Dy(r);
99
	for(y = 0; y < h; y++)
100
		memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1);
101
 
102
	return r;
103
}
104
 
105
/* must be called with display locked */
106
static void
107
updatescreen(Rectangle r)
108
{
109
	Image* img;
110
	int b, bb;
111
 
112
	lockdisplay(display);
113
	if(r.max.x > Dx(screen->r) || r.max.y > Dy(screen->r)){
114
		r = clippixbuf(r, Dx(screen->r), Dy(screen->r));
115
		if(r.max.x == 0){
116
			unlockdisplay(display);
117
			return;
118
		}
119
	}
120
 
121
	/*
122
	 * assume load image fails only because of resize
123
	 */
124
	img = allocimage(display, r, screen->chan, 0, DNofill);
125
	if(img == nil)
126
		sysfatal("updatescreen: %r");
127
	b = Dx(r) * pixb * Dy(r);
128
	bb = loadimage(img, r, pixbuf, b);
129
	if(bb != b && verbose)
130
		fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb);
131
	draw(screen, rectaddpt(r, screen->r.min), img, nil, r.min);
132
	freeimage(img);
133
	unlockdisplay(display);
134
}
135
 
136
static void
137
fillrect(Rectangle r, int stride, uchar *color)
138
{
139
	int x, xe, y, off;
140
 
141
	y = r.min.y;
142
	off = y * stride;
143
	for(; y < r.max.y; y++){
144
		xe = off + r.max.x * pixb;
145
		for(x = off + r.min.x * pixb; x < xe; x += pixb)
146
			(*pixcp)(&pixbuf[x], color);
147
		off += stride;
148
	}
149
}
150
 
151
static void
152
loadbuf(Vnc *v, Rectangle r, int stride)
153
{
154
	int off, y;
155
 
156
	if(cvtpixels){
157
		y = r.min.y;
158
		off = y * stride;
159
		for(; y < r.max.y; y++){
160
			vncrdbytes(v, linebuf, Dx(r) * vpixb);
161
			(*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r));
162
			off += stride;
163
		}
164
	}else{
165
		y = r.min.y;
166
		off = y * stride;
167
		for(; y < r.max.y; y++){
168
			vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb);
169
			off += stride;
170
		}
171
	}
172
}
173
 
174
static Rectangle
175
hexrect(ushort u)
176
{
177
	int x, y, w, h;
178
 
179
	x = u>>12;
180
	y = (u>>8)&15;
181
	w = ((u>>4)&15)+1;
182
	h = (u&15)+1;
183
 
184
	return Rect(x, y, x+w, y+h);
185
}
186
 
187
 
188
static void
189
dohextile(Vnc *v, Rectangle r, int stride)
190
{
191
	ulong bg, fg, c;
192
	int enc, nsub, sx, sy, w, h, th, tw;
193
	Rectangle sr, ssr;
194
 
195
	fg = bg = 0;
196
	h = Dy(r);
197
	w = Dx(r);
198
	for(sy = 0; sy < h; sy += HextileDim){
199
		th = h - sy;
200
		if(th > HextileDim)
201
			th = HextileDim;
202
		for(sx = 0; sx < w; sx += HextileDim){
203
			tw = w - sx;
204
			if(tw > HextileDim)
205
				tw = HextileDim;
206
 
207
			sr = Rect(sx, sy, sx + tw, sy + th);
208
			enc = vncrdchar(v);
209
			if(enc & HextileRaw){
210
				loadbuf(v, sr, stride);
211
				continue;
212
			}
213
 
214
			if(enc & HextileBack)
215
				vncrdcolor(v, (uchar*)&bg);
216
			fillrect(sr, stride, (uchar*)&bg);
217
 
218
			if(enc & HextileFore)
219
				vncrdcolor(v, (uchar*)&fg);
220
 
221
			if(enc & HextileRects){
222
				nsub = vncrdchar(v);
223
				(*pixcp)((uchar*)&c, (uchar*)&fg);
224
				while(nsub-- > 0){
225
					if(enc & HextileCols)
226
						vncrdcolor(v, (uchar*)&c);
227
					ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min);
228
					fillrect(ssr, stride, (uchar*)&c);
229
				}
230
			}
231
		}
232
	}
233
}
234
 
235
static void
236
dorectangle(Vnc *v)
237
{
238
	ulong type;
239
	long n, stride;
240
	ulong color;
241
	Point p;
242
	Rectangle r, subr, maxr;
243
 
244
	r = vncrdrect(v);
245
	if(r.min.x == r.max.x || r.min.y == r.max.y)
246
		return;
247
	if(!rectinrect(r, Rpt(ZP, v->dim)))
248
		sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim));
249
	stride = Dx(r) * pixb;
250
	type = vncrdlong(v);
251
	switch(type){
252
	default:
253
		sysfatal("bad rectangle encoding from server");
254
		break;
255
	case EncRaw:
256
		loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride);
257
		updatescreen(r);
258
		break;
259
 
260
	case EncCopyRect:
261
		p = vncrdpoint(v);
262
		lockdisplay(display);
263
		p = addpt(p, screen->r.min);
264
		r = rectaddpt(r, screen->r.min);
265
		draw(screen, r, screen, nil, p);
266
		unlockdisplay(display);
267
		break;
268
 
269
	case EncRre:
270
	case EncCorre:
271
		maxr = Rpt(ZP, Pt(Dx(r), Dy(r)));
272
		n = vncrdlong(v);
273
		vncrdcolor(v, (uchar*)&color);
274
		fillrect(maxr, stride, (uchar*)&color);
275
		while(n-- > 0){
276
			vncrdcolor(v, (uchar*)&color);
277
			if(type == EncRre)
278
				subr = vncrdrect(v);
279
			else
280
				subr = vncrdcorect(v);
281
			if(!rectinrect(subr, maxr))
282
				sysfatal("bad encoding from server");
283
			fillrect(subr, stride, (uchar*)&color);
284
		}
285
		updatescreen(r);
286
		break;
287
 
288
	case EncHextile:
289
		dohextile(v, r, stride);
290
		updatescreen(r);
291
		break;
292
 
293
	case EncMouseWarp:
294
		mousewarp(r.min);
295
		break;
296
	}
297
}
298
 
299
static void
300
pixcp8(uchar *dst, uchar *src)
301
{
302
	*dst = *src;
303
}
304
 
305
static void
306
pixcp16(uchar *dst, uchar *src)
307
{
308
	*(ushort*)dst = *(ushort*)src;
309
}
310
 
311
static void
312
pixcp32(uchar *dst, uchar *src)
313
{
314
	*(ulong*)dst = *(ulong*)src;
315
}
316
 
317
static void
318
pixcp24(uchar *dst, uchar *src)
319
{
320
	dst[0] = src[0];
321
	dst[1] = src[1];
322
	dst[2] = src[2];
323
}
324
 
325
static int
326
calcpixb(int bpp)
327
{
328
	if(bpp / 8 * 8 != bpp)
329
		sysfatal("can't handle your screen");
330
	return bpp / 8;
331
}
332
 
333
void
334
readfromserver(Vnc *v)
335
{
336
	uchar type;
337
	uchar junk[100];
338
	long n;
339
 
340
	vpixb = calcpixb(v->bpp);
341
	pixb = calcpixb(screen->depth);
342
	switch(pixb){
343
	case 1:
344
		pixcp = pixcp8;
345
		break;
346
	case 2:
347
		pixcp = pixcp16;
348
		break;
349
	case 3:
350
		pixcp = pixcp24;
351
		break;
352
	case 4:
353
		pixcp = pixcp32;
354
		break;
355
	default:
356
		sysfatal("can't handle your screen: bad depth %d", pixb);
357
	}
358
	linebuf = malloc(v->dim.x * vpixb);
359
	pixbuf = malloc(v->dim.x * pixb * v->dim.y);
360
	if(linebuf == nil || pixbuf == nil)
361
		sysfatal("can't allocate pix decompression storage");
362
	for(;;){
363
		type = vncrdchar(v);
364
		switch(type){
365
		default:
366
			sysfatal("bad message from server");
367
			break;
368
		case MFrameUpdate:
369
			vncrdchar(v);
370
			n = vncrdshort(v);
371
			while(n-- > 0)
372
				dorectangle(v);
373
			flushimage(display, 1);
374
			requestupdate(v, 1);
375
			break;
376
 
377
		case MSetCmap:
378
			vncrdbytes(v, junk, 3);
379
			n = vncrdshort(v);
380
			vncgobble(v, n*3*2);
381
			break;
382
 
383
		case MBell:
384
			break;
385
 
386
		case MSAck:
387
			break;
388
 
389
		case MSCut:
390
			vncrdbytes(v, junk, 3);
391
			n = vncrdlong(v);
392
			writesnarf(v, n);
393
			break;
394
		}
395
	}
396
}