19a747e4fSDavid du Colombier #include "vnc.h" 29a747e4fSDavid du Colombier #include "vncv.h" 39a747e4fSDavid du Colombier 49a747e4fSDavid du Colombier static struct { 59a747e4fSDavid du Colombier char *name; 69a747e4fSDavid du Colombier int num; 79a747e4fSDavid du Colombier } enctab[] = { 89a747e4fSDavid du Colombier "copyrect", EncCopyRect, 99a747e4fSDavid du Colombier "corre", EncCorre, 109a747e4fSDavid du Colombier "hextile", EncHextile, 119a747e4fSDavid du Colombier "raw", EncRaw, 129a747e4fSDavid du Colombier "rre", EncRre, 139a747e4fSDavid du Colombier "mousewarp", EncMouseWarp, 149a747e4fSDavid du Colombier }; 159a747e4fSDavid du Colombier 169a747e4fSDavid du Colombier static uchar *pixbuf; 179a747e4fSDavid du Colombier static uchar *linebuf; 189a747e4fSDavid du Colombier static int vpixb; 199a747e4fSDavid du Colombier static int pixb; 209a747e4fSDavid du Colombier static void (*pixcp)(uchar*, uchar*); 219a747e4fSDavid du Colombier 229a747e4fSDavid du Colombier static void 239a747e4fSDavid du Colombier vncrdcolor(Vnc *v, uchar *color) 249a747e4fSDavid du Colombier { 259a747e4fSDavid du Colombier vncrdbytes(v, color, vpixb); 269a747e4fSDavid du Colombier 279a747e4fSDavid du Colombier if(cvtpixels) 289a747e4fSDavid du Colombier (*cvtpixels)(color, color, 1); 299a747e4fSDavid du Colombier } 309a747e4fSDavid du Colombier 319a747e4fSDavid du Colombier void 329a747e4fSDavid du Colombier sendencodings(Vnc *v) 339a747e4fSDavid du Colombier { 349a747e4fSDavid du Colombier char *f[10]; 359a747e4fSDavid du Colombier int enc[10], nenc, i, j, nf; 369a747e4fSDavid du Colombier 379a747e4fSDavid du Colombier nf = tokenize(encodings, f, nelem(f)); 389a747e4fSDavid du Colombier nenc = 0; 399a747e4fSDavid du Colombier for(i=0; i<nf; i++) { 409a747e4fSDavid du Colombier for(j=0; j<nelem(enctab); j++) 419a747e4fSDavid du Colombier if(strcmp(f[i], enctab[j].name) == 0) 429a747e4fSDavid du Colombier break; 439a747e4fSDavid du Colombier if(j == nelem(enctab)) { 449a747e4fSDavid du Colombier print("warning: unknown encoding %s\n", f[i]); 459a747e4fSDavid du Colombier continue; 469a747e4fSDavid du Colombier } 479a747e4fSDavid du Colombier enc[nenc++] = enctab[j].num; 489a747e4fSDavid du Colombier } 499a747e4fSDavid du Colombier 509a747e4fSDavid du Colombier vnclock(v); 519a747e4fSDavid du Colombier vncwrchar(v, MSetEnc); 529a747e4fSDavid du Colombier vncwrchar(v, 0); 539a747e4fSDavid du Colombier vncwrshort(v, nenc); 549a747e4fSDavid du Colombier for(i=0; i<nenc; i++) 559a747e4fSDavid du Colombier vncwrlong(v, enc[i]); 569a747e4fSDavid du Colombier vncflush(v); 579a747e4fSDavid du Colombier vncunlock(v); 589a747e4fSDavid du Colombier } 599a747e4fSDavid du Colombier 609a747e4fSDavid du Colombier void 619a747e4fSDavid du Colombier requestupdate(Vnc *v, int incremental) 629a747e4fSDavid du Colombier { 639a747e4fSDavid du Colombier int x, y; 649a747e4fSDavid du Colombier 659a747e4fSDavid du Colombier lockdisplay(display); 669a747e4fSDavid du Colombier x = Dx(screen->r); 679a747e4fSDavid du Colombier y = Dy(screen->r); 689a747e4fSDavid du Colombier unlockdisplay(display); 699a747e4fSDavid du Colombier if(x > v->dim.x) 709a747e4fSDavid du Colombier x = v->dim.x; 719a747e4fSDavid du Colombier if(y > v->dim.y) 729a747e4fSDavid du Colombier y = v->dim.y; 739a747e4fSDavid du Colombier vnclock(v); 749a747e4fSDavid du Colombier vncwrchar(v, MFrameReq); 759a747e4fSDavid du Colombier vncwrchar(v, incremental); 769a747e4fSDavid du Colombier vncwrrect(v, Rpt(ZP, Pt(x, y))); 779a747e4fSDavid du Colombier vncflush(v); 789a747e4fSDavid du Colombier vncunlock(v); 799a747e4fSDavid du Colombier } 809a747e4fSDavid du Colombier 819a747e4fSDavid du Colombier static Rectangle 829a747e4fSDavid du Colombier clippixbuf(Rectangle r, int maxx, int maxy) 839a747e4fSDavid du Colombier { 849a747e4fSDavid du Colombier int y, h, stride1, stride2; 859a747e4fSDavid du Colombier 869a747e4fSDavid du Colombier if(r.min.x > maxx || r.min.y > maxy){ 879a747e4fSDavid du Colombier r.max.x = 0; 889a747e4fSDavid du Colombier return r; 899a747e4fSDavid du Colombier } 909a747e4fSDavid du Colombier if(r.max.y > maxy) 919a747e4fSDavid du Colombier r.max.y = maxy; 929a747e4fSDavid du Colombier if(r.max.x <= maxx) 939a747e4fSDavid du Colombier return r; 949a747e4fSDavid du Colombier 959a747e4fSDavid du Colombier stride2 = Dx(r) * pixb; 969a747e4fSDavid du Colombier r.max.x = maxx; 979a747e4fSDavid du Colombier stride1 = Dx(r) * pixb; 989a747e4fSDavid du Colombier h = Dy(r); 999a747e4fSDavid du Colombier for(y = 0; y < h; y++) 1009a747e4fSDavid du Colombier memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1); 1019a747e4fSDavid du Colombier 1029a747e4fSDavid du Colombier return r; 1039a747e4fSDavid du Colombier } 1049a747e4fSDavid du Colombier 1059a747e4fSDavid du Colombier /* must be called with display locked */ 1069a747e4fSDavid du Colombier static void 1079a747e4fSDavid du Colombier updatescreen(Rectangle r) 1089a747e4fSDavid du Colombier { 1099a747e4fSDavid du Colombier int b, bb; 1109a747e4fSDavid du Colombier 1119a747e4fSDavid du Colombier lockdisplay(display); 1129a747e4fSDavid du Colombier if(r.max.x > Dx(screen->r) || r.max.y > Dy(screen->r)){ 1139a747e4fSDavid du Colombier r = clippixbuf(r, Dx(screen->r), Dy(screen->r)); 1149a747e4fSDavid du Colombier if(r.max.x == 0){ 1159a747e4fSDavid du Colombier unlockdisplay(display); 1169a747e4fSDavid du Colombier return; 1179a747e4fSDavid du Colombier } 1189a747e4fSDavid du Colombier } 1199a747e4fSDavid du Colombier 1209a747e4fSDavid du Colombier /* 1219a747e4fSDavid du Colombier * assume load image fails only because of resize 1229a747e4fSDavid du Colombier */ 1239a747e4fSDavid du Colombier b = Dx(r) * pixb * Dy(r); 1249a747e4fSDavid du Colombier bb = loadimage(screen, rectaddpt(r, screen->r.min), pixbuf, b); 1259a747e4fSDavid du Colombier if(bb != b && verbose) 1269a747e4fSDavid du Colombier fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb); 1279a747e4fSDavid du Colombier unlockdisplay(display); 1289a747e4fSDavid du Colombier } 1299a747e4fSDavid du Colombier 1309a747e4fSDavid du Colombier static void 1319a747e4fSDavid du Colombier fillrect(Rectangle r, int stride, uchar *color) 1329a747e4fSDavid du Colombier { 1339a747e4fSDavid du Colombier int x, xe, y, off; 1349a747e4fSDavid du Colombier 1359a747e4fSDavid du Colombier y = r.min.y; 1369a747e4fSDavid du Colombier off = y * stride; 1379a747e4fSDavid du Colombier for(; y < r.max.y; y++){ 1389a747e4fSDavid du Colombier xe = off + r.max.x * pixb; 1399a747e4fSDavid du Colombier for(x = off + r.min.x * pixb; x < xe; x += pixb) 1409a747e4fSDavid du Colombier (*pixcp)(&pixbuf[x], color); 1419a747e4fSDavid du Colombier off += stride; 1429a747e4fSDavid du Colombier } 1439a747e4fSDavid du Colombier } 1449a747e4fSDavid du Colombier 1459a747e4fSDavid du Colombier static void 1469a747e4fSDavid du Colombier loadbuf(Vnc *v, Rectangle r, int stride) 1479a747e4fSDavid du Colombier { 1489a747e4fSDavid du Colombier int off, y; 1499a747e4fSDavid du Colombier 1509a747e4fSDavid du Colombier if(cvtpixels){ 1519a747e4fSDavid du Colombier y = r.min.y; 1529a747e4fSDavid du Colombier off = y * stride; 1539a747e4fSDavid du Colombier for(; y < r.max.y; y++){ 1549a747e4fSDavid du Colombier vncrdbytes(v, linebuf, Dx(r) * vpixb); 1559a747e4fSDavid du Colombier (*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r)); 1569a747e4fSDavid du Colombier off += stride; 1579a747e4fSDavid du Colombier } 1589a747e4fSDavid du Colombier }else{ 1599a747e4fSDavid du Colombier y = r.min.y; 1609a747e4fSDavid du Colombier off = y * stride; 1619a747e4fSDavid du Colombier for(; y < r.max.y; y++){ 1629a747e4fSDavid du Colombier vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb); 1639a747e4fSDavid du Colombier off += stride; 1649a747e4fSDavid du Colombier } 1659a747e4fSDavid du Colombier } 1669a747e4fSDavid du Colombier } 1679a747e4fSDavid du Colombier 1689a747e4fSDavid du Colombier static Rectangle 1699a747e4fSDavid du Colombier hexrect(ushort u) 1709a747e4fSDavid du Colombier { 1719a747e4fSDavid du Colombier int x, y, w, h; 1729a747e4fSDavid du Colombier 1739a747e4fSDavid du Colombier x = u>>12; 1749a747e4fSDavid du Colombier y = (u>>8)&15; 1759a747e4fSDavid du Colombier w = ((u>>4)&15)+1; 1769a747e4fSDavid du Colombier h = (u&15)+1; 1779a747e4fSDavid du Colombier 1789a747e4fSDavid du Colombier return Rect(x, y, x+w, y+h); 1799a747e4fSDavid du Colombier } 1809a747e4fSDavid du Colombier 1819a747e4fSDavid du Colombier 1829a747e4fSDavid du Colombier static void 1839a747e4fSDavid du Colombier dohextile(Vnc *v, Rectangle r, int stride) 1849a747e4fSDavid du Colombier { 1859a747e4fSDavid du Colombier ulong bg, fg, c; 1869a747e4fSDavid du Colombier int enc, nsub, sx, sy, w, h, th, tw; 1879a747e4fSDavid du Colombier Rectangle sr, ssr; 1889a747e4fSDavid du Colombier 1899a747e4fSDavid du Colombier fg = bg = 0; 1909a747e4fSDavid du Colombier h = Dy(r); 1919a747e4fSDavid du Colombier w = Dx(r); 1929a747e4fSDavid du Colombier for(sy = 0; sy < h; sy += HextileDim){ 1939a747e4fSDavid du Colombier th = h - sy; 1949a747e4fSDavid du Colombier if(th > HextileDim) 1959a747e4fSDavid du Colombier th = HextileDim; 1969a747e4fSDavid du Colombier for(sx = 0; sx < w; sx += HextileDim){ 1979a747e4fSDavid du Colombier tw = w - sx; 1989a747e4fSDavid du Colombier if(tw > HextileDim) 1999a747e4fSDavid du Colombier tw = HextileDim; 2009a747e4fSDavid du Colombier 2019a747e4fSDavid du Colombier sr = Rect(sx, sy, sx + tw, sy + th); 2029a747e4fSDavid du Colombier enc = vncrdchar(v); 2039a747e4fSDavid du Colombier if(enc & HextileRaw) { 2049a747e4fSDavid du Colombier loadbuf(v, sr, stride); 2059a747e4fSDavid du Colombier continue; 2069a747e4fSDavid du Colombier } 2079a747e4fSDavid du Colombier 2089a747e4fSDavid du Colombier if(enc & HextileBack) 2099a747e4fSDavid du Colombier vncrdcolor(v, (uchar*)&bg); 2109a747e4fSDavid du Colombier fillrect(sr, stride, (uchar*)&bg); 2119a747e4fSDavid du Colombier 2129a747e4fSDavid du Colombier if(enc & HextileFore) 2139a747e4fSDavid du Colombier vncrdcolor(v, (uchar*)&fg); 2149a747e4fSDavid du Colombier 2159a747e4fSDavid du Colombier if(enc & HextileRects) { 2169a747e4fSDavid du Colombier nsub = vncrdchar(v); 2179a747e4fSDavid du Colombier (*pixcp)((uchar*)&c, (uchar*)&fg); 2189a747e4fSDavid du Colombier while(nsub-- > 0) { 2199a747e4fSDavid du Colombier if(enc & HextileCols) 2209a747e4fSDavid du Colombier vncrdcolor(v, (uchar*)&c); 2219a747e4fSDavid du Colombier ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min); 2229a747e4fSDavid du Colombier fillrect(ssr, stride, (uchar*)&c); 2239a747e4fSDavid du Colombier } 2249a747e4fSDavid du Colombier } 2259a747e4fSDavid du Colombier } 2269a747e4fSDavid du Colombier } 2279a747e4fSDavid du Colombier } 2289a747e4fSDavid du Colombier 2299a747e4fSDavid du Colombier static void 2309a747e4fSDavid du Colombier dorectangle(Vnc *v) 2319a747e4fSDavid du Colombier { 2329a747e4fSDavid du Colombier ulong type; 2339a747e4fSDavid du Colombier long n, stride; 2349a747e4fSDavid du Colombier ulong color; 2359a747e4fSDavid du Colombier Point p; 2369a747e4fSDavid du Colombier Rectangle r, subr, maxr; 2379a747e4fSDavid du Colombier 2389a747e4fSDavid du Colombier r = vncrdrect(v); 2399a747e4fSDavid du Colombier if(!rectinrect(r, Rpt(ZP, v->dim)) 2409a747e4fSDavid du Colombier || r.min.x == r.max.x || r.min.y == r.max.y) 2419a747e4fSDavid du Colombier sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim)); 2429a747e4fSDavid du Colombier stride = Dx(r) * pixb; 2439a747e4fSDavid du Colombier type = vncrdlong(v); 2449a747e4fSDavid du Colombier switch(type) { 2459a747e4fSDavid du Colombier default: 2469a747e4fSDavid du Colombier sysfatal("bad rectangle encoding from server"); 2479a747e4fSDavid du Colombier break; 2489a747e4fSDavid du Colombier case EncRaw: 2499a747e4fSDavid du Colombier loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride); 2509a747e4fSDavid du Colombier updatescreen(r); 2519a747e4fSDavid du Colombier break; 2529a747e4fSDavid du Colombier 2539a747e4fSDavid du Colombier case EncCopyRect: 2549a747e4fSDavid du Colombier p = vncrdpoint(v); 2559a747e4fSDavid du Colombier lockdisplay(display); 2569a747e4fSDavid du Colombier p = addpt(p, screen->r.min); 2579a747e4fSDavid du Colombier r = rectaddpt(r, screen->r.min); 2589a747e4fSDavid du Colombier draw(screen, r, screen, nil, p); 2599a747e4fSDavid du Colombier unlockdisplay(display); 2609a747e4fSDavid du Colombier break; 2619a747e4fSDavid du Colombier 2629a747e4fSDavid du Colombier case EncRre: 2639a747e4fSDavid du Colombier case EncCorre: 2649a747e4fSDavid du Colombier maxr = Rpt(ZP, Pt(Dx(r), Dy(r))); 2659a747e4fSDavid du Colombier n = vncrdlong(v); 2669a747e4fSDavid du Colombier vncrdcolor(v, (uchar*)&color); 2679a747e4fSDavid du Colombier fillrect(maxr, stride, (uchar*)&color); 2689a747e4fSDavid du Colombier while(n-- > 0) { 2699a747e4fSDavid du Colombier vncrdcolor(v, (uchar*)&color); 2709a747e4fSDavid du Colombier if(type == EncRre) 2719a747e4fSDavid du Colombier subr = vncrdrect(v); 2729a747e4fSDavid du Colombier else 2739a747e4fSDavid du Colombier subr = vncrdcorect(v); 2749a747e4fSDavid du Colombier if(!rectinrect(subr, maxr)) 2759a747e4fSDavid du Colombier sysfatal("bad encoding from server"); 2769a747e4fSDavid du Colombier fillrect(subr, stride, (uchar*)&color); 2779a747e4fSDavid du Colombier } 2789a747e4fSDavid du Colombier updatescreen(r); 2799a747e4fSDavid du Colombier break; 2809a747e4fSDavid du Colombier 2819a747e4fSDavid du Colombier case EncHextile: 2829a747e4fSDavid du Colombier dohextile(v, r, stride); 2839a747e4fSDavid du Colombier updatescreen(r); 2849a747e4fSDavid du Colombier break; 285*d9306527SDavid du Colombier 2869a747e4fSDavid du Colombier case EncMouseWarp: 2879a747e4fSDavid du Colombier mousewarp(r.min); 2889a747e4fSDavid du Colombier break; 2899a747e4fSDavid du Colombier } 2909a747e4fSDavid du Colombier } 2919a747e4fSDavid du Colombier 2929a747e4fSDavid du Colombier static void 2939a747e4fSDavid du Colombier pixcp8(uchar *dst, uchar *src) 2949a747e4fSDavid du Colombier { 2959a747e4fSDavid du Colombier *dst = *src; 2969a747e4fSDavid du Colombier } 2979a747e4fSDavid du Colombier 2989a747e4fSDavid du Colombier static void 2999a747e4fSDavid du Colombier pixcp16(uchar *dst, uchar *src) 3009a747e4fSDavid du Colombier { 3019a747e4fSDavid du Colombier *(ushort*)dst = *(ushort*)src; 3029a747e4fSDavid du Colombier } 3039a747e4fSDavid du Colombier 3049a747e4fSDavid du Colombier static void 3059a747e4fSDavid du Colombier pixcp32(uchar *dst, uchar *src) 3069a747e4fSDavid du Colombier { 3079a747e4fSDavid du Colombier *(ulong*)dst = *(ulong*)src; 3089a747e4fSDavid du Colombier } 3099a747e4fSDavid du Colombier 3109a747e4fSDavid du Colombier static void 3119a747e4fSDavid du Colombier pixcp24(uchar *dst, uchar *src) 3129a747e4fSDavid du Colombier { 3139a747e4fSDavid du Colombier dst[0] = src[0]; 3149a747e4fSDavid du Colombier dst[1] = src[1]; 3159a747e4fSDavid du Colombier dst[2] = src[2]; 3169a747e4fSDavid du Colombier } 3179a747e4fSDavid du Colombier 3189a747e4fSDavid du Colombier static int 3199a747e4fSDavid du Colombier calcpixb(int bpp) 3209a747e4fSDavid du Colombier { 3219a747e4fSDavid du Colombier if(bpp / 8 * 8 != bpp) 3229a747e4fSDavid du Colombier sysfatal("can't handle your screen"); 3239a747e4fSDavid du Colombier return bpp / 8; 3249a747e4fSDavid du Colombier } 3259a747e4fSDavid du Colombier 3269a747e4fSDavid du Colombier void 3279a747e4fSDavid du Colombier readfromserver(Vnc *v) 3289a747e4fSDavid du Colombier { 3299a747e4fSDavid du Colombier uchar type; 3309a747e4fSDavid du Colombier uchar junk[100]; 3319a747e4fSDavid du Colombier long n; 3329a747e4fSDavid du Colombier 3339a747e4fSDavid du Colombier vpixb = calcpixb(v->bpp); 3349a747e4fSDavid du Colombier pixb = calcpixb(screen->depth); 3359a747e4fSDavid du Colombier switch(pixb){ 336*d9306527SDavid du Colombier case 1: 337*d9306527SDavid du Colombier pixcp = pixcp8; 338*d9306527SDavid du Colombier break; 339*d9306527SDavid du Colombier case 2: 340*d9306527SDavid du Colombier pixcp = pixcp16; 341*d9306527SDavid du Colombier break; 342*d9306527SDavid du Colombier case 3: 343*d9306527SDavid du Colombier pixcp = pixcp24; 344*d9306527SDavid du Colombier break; 345*d9306527SDavid du Colombier case 4: 346*d9306527SDavid du Colombier pixcp = pixcp32; 347*d9306527SDavid du Colombier break; 3489a747e4fSDavid du Colombier default: 349*d9306527SDavid du Colombier sysfatal("can't handle your screen: bad depth %d", pixb); 3509a747e4fSDavid du Colombier } 3519a747e4fSDavid du Colombier linebuf = malloc(v->dim.x * vpixb); 3529a747e4fSDavid du Colombier pixbuf = malloc(v->dim.x * pixb * v->dim.y); 3539a747e4fSDavid du Colombier if(linebuf == nil || pixbuf == nil) 3549a747e4fSDavid du Colombier sysfatal("can't allocate pix decompression storage"); 3559a747e4fSDavid du Colombier for(;;) { 3569a747e4fSDavid du Colombier type = vncrdchar(v); 3579a747e4fSDavid du Colombier switch(type) { 3589a747e4fSDavid du Colombier default: 3599a747e4fSDavid du Colombier sysfatal("bad message from server"); 3609a747e4fSDavid du Colombier break; 3619a747e4fSDavid du Colombier case MFrameUpdate: 3629a747e4fSDavid du Colombier vncrdchar(v); 3639a747e4fSDavid du Colombier n = vncrdshort(v); 3649a747e4fSDavid du Colombier while(n-- > 0) 3659a747e4fSDavid du Colombier dorectangle(v); 3669a747e4fSDavid du Colombier flushimage(display, 1); 3679a747e4fSDavid du Colombier requestupdate(v, 1); 3689a747e4fSDavid du Colombier break; 3699a747e4fSDavid du Colombier 3709a747e4fSDavid du Colombier case MSetCmap: 3719a747e4fSDavid du Colombier vncrdbytes(v, junk, 3); 3729a747e4fSDavid du Colombier n = vncrdshort(v); 3739a747e4fSDavid du Colombier vncgobble(v, n*3*2); 3749a747e4fSDavid du Colombier break; 3759a747e4fSDavid du Colombier 3769a747e4fSDavid du Colombier case MBell: 3779a747e4fSDavid du Colombier break; 3789a747e4fSDavid du Colombier 3799a747e4fSDavid du Colombier case MSCut: 3809a747e4fSDavid du Colombier vncrdbytes(v, junk, 3); 3819a747e4fSDavid du Colombier n = vncrdlong(v); 3829a747e4fSDavid du Colombier writesnarf(v, n); 3839a747e4fSDavid du Colombier break; 3849a747e4fSDavid du Colombier } 3859a747e4fSDavid du Colombier } 3869a747e4fSDavid du Colombier } 387