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