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
vncrdcolor(Vnc * v,uchar * color)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
sendencodings(Vnc * v)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
requestupdate(Vnc * v,int incremental)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
clippixbuf(Rectangle r,int maxx,int maxy)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
updatescreen(Rectangle r)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
fillrect(Rectangle r,int stride,uchar * color)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
loadbuf(Vnc * v,Rectangle r,int stride)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
hexrect(ushort u)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
dohextile(Vnc * v,Rectangle r,int stride)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
dorectangle(Vnc * v)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
pixcp8(uchar * dst,uchar * src)300 pixcp8(uchar *dst, uchar *src)
301 {
302 *dst = *src;
303 }
304
305 static void
pixcp16(uchar * dst,uchar * src)306 pixcp16(uchar *dst, uchar *src)
307 {
308 *(ushort*)dst = *(ushort*)src;
309 }
310
311 static void
pixcp32(uchar * dst,uchar * src)312 pixcp32(uchar *dst, uchar *src)
313 {
314 *(ulong*)dst = *(ulong*)src;
315 }
316
317 static void
pixcp24(uchar * dst,uchar * src)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
calcpixb(int bpp)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
readfromserver(Vnc * v)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 }
397