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