]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/draw.c
vnc: don't prompt for password on auth_respond() failure
[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 };
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         flushimage(display, 1);
67         x = Dx(screen->r);
68         y = Dy(screen->r);
69         unlockdisplay(display);
70         if(x > v->dim.x)
71                 x = v->dim.x;
72         if(y > v->dim.y)
73                 y = v->dim.y;
74         vnclock(v);
75         vncwrchar(v, MFrameReq);
76         vncwrchar(v, incremental);
77         vncwrrect(v, Rpt(ZP, Pt(x, y)));
78         vncflush(v);
79         vncunlock(v);
80 }
81
82 static Rectangle
83 clippixbuf(Rectangle r, int maxx, int maxy)
84 {
85         int y, h, stride1, stride2;
86
87         if(r.min.x > maxx || r.min.y > maxy){
88                 r.max.x = 0;
89                 return r;
90         }
91         if(r.max.y > maxy)
92                 r.max.y = maxy;
93         if(r.max.x <= maxx)
94                 return r;
95
96         stride2 = Dx(r) * pixb;
97         r.max.x = maxx;
98         stride1 = Dx(r) * pixb;
99         h = Dy(r);
100         for(y = 0; y < h; y++)
101                 memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1);
102
103         return r;
104 }
105
106 /* must be called with display locked */
107 static void
108 updatescreen(Rectangle r)
109 {
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         b = Dx(r) * pixb * Dy(r);
125         bb = loadimage(screen, rectaddpt(r, screen->r.min), pixbuf, b);
126         if(bb != b && verbose)
127                 fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb);
128         unlockdisplay(display);
129 }
130
131 static void
132 fillrect(Rectangle r, int stride, uchar *color)
133 {
134         int x, xe, y, off;
135
136         y = r.min.y;
137         off = y * stride;
138         for(; y < r.max.y; y++){
139                 xe = off + r.max.x * pixb;
140                 for(x = off + r.min.x * pixb; x < xe; x += pixb)
141                         (*pixcp)(&pixbuf[x], color);
142                 off += stride;
143         }
144 }
145
146 static void
147 loadbuf(Vnc *v, Rectangle r, int stride)
148 {
149         int off, y;
150
151         if(cvtpixels){
152                 y = r.min.y;
153                 off = y * stride;
154                 for(; y < r.max.y; y++){
155                         vncrdbytes(v, linebuf, Dx(r) * vpixb);
156                         (*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r));
157                         off += stride;
158                 }
159         }else{
160                 y = r.min.y;
161                 off = y * stride;
162                 for(; y < r.max.y; y++){
163                         vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb);
164                         off += stride;
165                 }
166         }
167 }
168
169 static Rectangle
170 hexrect(ushort u)
171 {
172         int x, y, w, h;
173
174         x = u>>12;
175         y = (u>>8)&15;
176         w = ((u>>4)&15)+1;
177         h = (u&15)+1;
178
179         return Rect(x, y, x+w, y+h);
180 }
181
182
183 static void
184 dohextile(Vnc *v, Rectangle r, int stride)
185 {
186         ulong bg, fg, c;
187         int enc, nsub, sx, sy, w, h, th, tw;
188         Rectangle sr, ssr;
189
190         fg = bg = 0;
191         h = Dy(r);
192         w = Dx(r);
193         for(sy = 0; sy < h; sy += HextileDim){
194                 th = h - sy;
195                 if(th > HextileDim)
196                         th = HextileDim;
197                 for(sx = 0; sx < w; sx += HextileDim){
198                         tw = w - sx;
199                         if(tw > HextileDim)
200                                 tw = HextileDim;
201
202                         sr = Rect(sx, sy, sx + tw, sy + th);
203                         enc = vncrdchar(v);
204                         if(enc & HextileRaw){
205                                 loadbuf(v, sr, stride);
206                                 continue;
207                         }
208
209                         if(enc & HextileBack)
210                                 vncrdcolor(v, (uchar*)&bg);
211                         fillrect(sr, stride, (uchar*)&bg);
212
213                         if(enc & HextileFore)
214                                 vncrdcolor(v, (uchar*)&fg);
215
216                         if(enc & HextileRects){
217                                 nsub = vncrdchar(v);
218                                 (*pixcp)((uchar*)&c, (uchar*)&fg);
219                                 while(nsub-- > 0){
220                                         if(enc & HextileCols)
221                                                 vncrdcolor(v, (uchar*)&c);
222                                         ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min);
223                                         fillrect(ssr, stride, (uchar*)&c);
224                                 }
225                         }
226                 }
227         }
228 }
229
230 static void
231 dorectangle(Vnc *v)
232 {
233         ulong type;
234         long n, stride;
235         ulong color;
236         Point p;
237         Rectangle r, subr, maxr;
238
239         r = vncrdrect(v);
240         if(!rectinrect(r, Rpt(ZP, v->dim)))
241                 sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim));
242         stride = Dx(r) * pixb;
243         type = vncrdlong(v);
244         switch(type){
245         default:
246                 sysfatal("bad rectangle encoding from server");
247                 break;
248         case EncRaw:
249                 loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride);
250                 updatescreen(r);
251                 break;
252
253         case EncCopyRect:
254                 p = vncrdpoint(v);
255                 lockdisplay(display);
256                 p = addpt(p, screen->r.min);
257                 r = rectaddpt(r, screen->r.min);
258                 draw(screen, r, screen, nil, p);
259                 unlockdisplay(display);
260                 break;
261
262         case EncRre:
263         case EncCorre:
264                 maxr = Rpt(ZP, Pt(Dx(r), Dy(r)));
265                 n = vncrdlong(v);
266                 vncrdcolor(v, (uchar*)&color);
267                 fillrect(maxr, stride, (uchar*)&color);
268                 while(n-- > 0){
269                         vncrdcolor(v, (uchar*)&color);
270                         if(type == EncRre)
271                                 subr = vncrdrect(v);
272                         else
273                                 subr = vncrdcorect(v);
274                         if(!rectinrect(subr, maxr))
275                                 sysfatal("bad encoding from server");
276                         fillrect(subr, stride, (uchar*)&color);
277                 }
278                 updatescreen(r);
279                 break;
280
281         case EncHextile:
282                 dohextile(v, r, stride);
283                 updatescreen(r);
284                 break;
285
286         case EncMouseWarp:
287                 mousewarp(r.min);
288                 break;
289         }
290 }
291
292 static void
293 pixcp8(uchar *dst, uchar *src)
294 {
295         *dst = *src;
296 }
297
298 static void
299 pixcp16(uchar *dst, uchar *src)
300 {
301         *(ushort*)dst = *(ushort*)src;
302 }
303
304 static void
305 pixcp32(uchar *dst, uchar *src)
306 {
307         *(ulong*)dst = *(ulong*)src;
308 }
309
310 static void
311 pixcp24(uchar *dst, uchar *src)
312 {
313         dst[0] = src[0];
314         dst[1] = src[1];
315         dst[2] = src[2];
316 }
317
318 static int
319 calcpixb(int bpp)
320 {
321         if(bpp / 8 * 8 != bpp)
322                 sysfatal("can't handle your screen");
323         return bpp / 8;
324 }
325
326 void
327 readfromserver(Vnc *v)
328 {
329         uchar type;
330         uchar junk[100];
331         long n;
332
333         vpixb = calcpixb(v->bpp);
334         pixb = calcpixb(screen->depth);
335         switch(pixb){
336         case 1:
337                 pixcp = pixcp8;
338                 break;
339         case 2:
340                 pixcp = pixcp16;
341                 break;
342         case 3:
343                 pixcp = pixcp24;
344                 break;
345         case 4:
346                 pixcp = pixcp32;
347                 break;
348         default:
349                 sysfatal("can't handle your screen: bad depth %d", pixb);
350         }
351         linebuf = malloc(v->dim.x * vpixb);
352         pixbuf = malloc(v->dim.x * pixb * v->dim.y);
353         if(linebuf == nil || pixbuf == nil)
354                 sysfatal("can't allocate pix decompression storage");
355         for(;;){
356                 type = vncrdchar(v);
357                 switch(type){
358                 default:
359                         sysfatal("bad message from server");
360                         break;
361                 case MFrameUpdate:
362                         vncrdchar(v);
363                         n = vncrdshort(v);
364                         while(n-- > 0)
365                                 dorectangle(v);
366                         requestupdate(v, 1);
367                         break;
368
369                 case MSetCmap:
370                         vncrdbytes(v, junk, 3);
371                         n = vncrdshort(v);
372                         vncgobble(v, n*3*2);
373                         break;
374
375                 case MBell:
376                         break;
377
378                 case MSAck:
379                         break;
380
381                 case MSCut:
382                         vncrdbytes(v, junk, 3);
383                         n = vncrdlong(v);
384                         writesnarf(v, n);
385                         break;
386                 }
387         }
388 }