123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- #include "vnc.h"
- #include "vncv.h"
- static struct {
- char *name;
- int num;
- } enctab[] = {
- "copyrect", EncCopyRect,
- "corre", EncCorre,
- "hextile", EncHextile,
- "raw", EncRaw,
- "rre", EncRre,
- "mousewarp", EncMouseWarp,
- };
- static uchar *pixbuf;
- static uchar *linebuf;
- static int vpixb;
- static int pixb;
- static void (*pixcp)(uchar*, uchar*);
- static void
- vncrdcolor(Vnc *v, uchar *color)
- {
- vncrdbytes(v, color, vpixb);
- if(cvtpixels)
- (*cvtpixels)(color, color, 1);
- }
- void
- sendencodings(Vnc *v)
- {
- char *f[10];
- int enc[10], nenc, i, j, nf;
- nf = tokenize(encodings, f, nelem(f));
- nenc = 0;
- for(i=0; i<nf; i++) {
- for(j=0; j<nelem(enctab); j++)
- if(strcmp(f[i], enctab[j].name) == 0)
- break;
- if(j == nelem(enctab)) {
- print("warning: unknown encoding %s\n", f[i]);
- continue;
- }
- enc[nenc++] = enctab[j].num;
- }
- vnclock(v);
- vncwrchar(v, MSetEnc);
- vncwrchar(v, 0);
- vncwrshort(v, nenc);
- for(i=0; i<nenc; i++)
- vncwrlong(v, enc[i]);
- vncflush(v);
- vncunlock(v);
- }
- void
- requestupdate(Vnc *v, int incremental)
- {
- int x, y;
- lockdisplay(display);
- x = Dx(screen->r);
- y = Dy(screen->r);
- unlockdisplay(display);
- if(x > v->dim.x)
- x = v->dim.x;
- if(y > v->dim.y)
- y = v->dim.y;
- vnclock(v);
- vncwrchar(v, MFrameReq);
- vncwrchar(v, incremental);
- vncwrrect(v, Rpt(ZP, Pt(x, y)));
- vncflush(v);
- vncunlock(v);
- }
- static Rectangle
- clippixbuf(Rectangle r, int maxx, int maxy)
- {
- int y, h, stride1, stride2;
- if(r.min.x > maxx || r.min.y > maxy){
- r.max.x = 0;
- return r;
- }
- if(r.max.y > maxy)
- r.max.y = maxy;
- if(r.max.x <= maxx)
- return r;
- stride2 = Dx(r) * pixb;
- r.max.x = maxx;
- stride1 = Dx(r) * pixb;
- h = Dy(r);
- for(y = 0; y < h; y++)
- memmove(&pixbuf[y * stride1], &pixbuf[y * stride2], stride1);
- return r;
- }
- /* must be called with display locked */
- static void
- updatescreen(Rectangle r)
- {
- int b, bb;
- lockdisplay(display);
- if(r.max.x > Dx(screen->r) || r.max.y > Dy(screen->r)){
- r = clippixbuf(r, Dx(screen->r), Dy(screen->r));
- if(r.max.x == 0){
- unlockdisplay(display);
- return;
- }
- }
- /*
- * assume load image fails only because of resize
- */
- b = Dx(r) * pixb * Dy(r);
- bb = loadimage(screen, rectaddpt(r, screen->r.min), pixbuf, b);
- if(bb != b && verbose)
- fprint(2, "loadimage %d on %R for %R returned %d: %r\n", b, rectaddpt(r, screen->r.min), screen->r, bb);
- unlockdisplay(display);
- }
- static void
- fillrect(Rectangle r, int stride, uchar *color)
- {
- int x, xe, y, off;
- y = r.min.y;
- off = y * stride;
- for(; y < r.max.y; y++){
- xe = off + r.max.x * pixb;
- for(x = off + r.min.x * pixb; x < xe; x += pixb)
- (*pixcp)(&pixbuf[x], color);
- off += stride;
- }
- }
- static void
- loadbuf(Vnc *v, Rectangle r, int stride)
- {
- int off, y;
- if(cvtpixels){
- y = r.min.y;
- off = y * stride;
- for(; y < r.max.y; y++){
- vncrdbytes(v, linebuf, Dx(r) * vpixb);
- (*cvtpixels)(&pixbuf[off + r.min.x * pixb], linebuf, Dx(r));
- off += stride;
- }
- }else{
- y = r.min.y;
- off = y * stride;
- for(; y < r.max.y; y++){
- vncrdbytes(v, &pixbuf[off + r.min.x * pixb], Dx(r) * pixb);
- off += stride;
- }
- }
- }
- static Rectangle
- hexrect(ushort u)
- {
- int x, y, w, h;
- x = u>>12;
- y = (u>>8)&15;
- w = ((u>>4)&15)+1;
- h = (u&15)+1;
- return Rect(x, y, x+w, y+h);
- }
- static void
- dohextile(Vnc *v, Rectangle r, int stride)
- {
- ulong bg, fg, c;
- int enc, nsub, sx, sy, w, h, th, tw;
- Rectangle sr, ssr;
- fg = bg = 0;
- h = Dy(r);
- w = Dx(r);
- for(sy = 0; sy < h; sy += HextileDim){
- th = h - sy;
- if(th > HextileDim)
- th = HextileDim;
- for(sx = 0; sx < w; sx += HextileDim){
- tw = w - sx;
- if(tw > HextileDim)
- tw = HextileDim;
- sr = Rect(sx, sy, sx + tw, sy + th);
- enc = vncrdchar(v);
- if(enc & HextileRaw) {
- loadbuf(v, sr, stride);
- continue;
- }
- if(enc & HextileBack)
- vncrdcolor(v, (uchar*)&bg);
- fillrect(sr, stride, (uchar*)&bg);
- if(enc & HextileFore)
- vncrdcolor(v, (uchar*)&fg);
- if(enc & HextileRects) {
- nsub = vncrdchar(v);
- (*pixcp)((uchar*)&c, (uchar*)&fg);
- while(nsub-- > 0) {
- if(enc & HextileCols)
- vncrdcolor(v, (uchar*)&c);
- ssr = rectaddpt(hexrect(vncrdshort(v)), sr.min);
- fillrect(ssr, stride, (uchar*)&c);
- }
- }
- }
- }
- }
- static void
- dorectangle(Vnc *v)
- {
- ulong type;
- long n, stride;
- ulong color;
- Point p;
- Rectangle r, subr, maxr;
- r = vncrdrect(v);
- if(r.min.x == r.max.x || r.min.y == r.max.y)
- return;
- if(!rectinrect(r, Rpt(ZP, v->dim)))
- sysfatal("bad rectangle from server: %R not in %R", r, Rpt(ZP, v->dim));
- stride = Dx(r) * pixb;
- type = vncrdlong(v);
- switch(type) {
- default:
- sysfatal("bad rectangle encoding from server");
- break;
- case EncRaw:
- loadbuf(v, Rpt(ZP, Pt(Dx(r), Dy(r))), stride);
- updatescreen(r);
- break;
- case EncCopyRect:
- p = vncrdpoint(v);
- lockdisplay(display);
- p = addpt(p, screen->r.min);
- r = rectaddpt(r, screen->r.min);
- draw(screen, r, screen, nil, p);
- unlockdisplay(display);
- break;
- case EncRre:
- case EncCorre:
- maxr = Rpt(ZP, Pt(Dx(r), Dy(r)));
- n = vncrdlong(v);
- vncrdcolor(v, (uchar*)&color);
- fillrect(maxr, stride, (uchar*)&color);
- while(n-- > 0) {
- vncrdcolor(v, (uchar*)&color);
- if(type == EncRre)
- subr = vncrdrect(v);
- else
- subr = vncrdcorect(v);
- if(!rectinrect(subr, maxr))
- sysfatal("bad encoding from server");
- fillrect(subr, stride, (uchar*)&color);
- }
- updatescreen(r);
- break;
- case EncHextile:
- dohextile(v, r, stride);
- updatescreen(r);
- break;
- case EncMouseWarp:
- mousewarp(r.min);
- break;
- }
- }
- static void
- pixcp8(uchar *dst, uchar *src)
- {
- *dst = *src;
- }
- static void
- pixcp16(uchar *dst, uchar *src)
- {
- *(ushort*)dst = *(ushort*)src;
- }
- static void
- pixcp32(uchar *dst, uchar *src)
- {
- *(ulong*)dst = *(ulong*)src;
- }
- static void
- pixcp24(uchar *dst, uchar *src)
- {
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- }
- static int
- calcpixb(int bpp)
- {
- if(bpp / 8 * 8 != bpp)
- sysfatal("can't handle your screen");
- return bpp / 8;
- }
- void
- readfromserver(Vnc *v)
- {
- uchar type;
- uchar junk[100];
- long n;
- vpixb = calcpixb(v->bpp);
- pixb = calcpixb(screen->depth);
- switch(pixb){
- case 1:
- pixcp = pixcp8;
- break;
- case 2:
- pixcp = pixcp16;
- break;
- case 3:
- pixcp = pixcp24;
- break;
- case 4:
- pixcp = pixcp32;
- break;
- default:
- sysfatal("can't handle your screen: bad depth %d", pixb);
- }
- linebuf = malloc(v->dim.x * vpixb);
- pixbuf = malloc(v->dim.x * pixb * v->dim.y);
- if(linebuf == nil || pixbuf == nil)
- sysfatal("can't allocate pix decompression storage");
- for(;;) {
- type = vncrdchar(v);
- switch(type) {
- default:
- sysfatal("bad message from server");
- break;
- case MFrameUpdate:
- vncrdchar(v);
- n = vncrdshort(v);
- while(n-- > 0)
- dorectangle(v);
- flushimage(display, 1);
- requestupdate(v, 1);
- break;
- case MSetCmap:
- vncrdbytes(v, junk, 3);
- n = vncrdshort(v);
- vncgobble(v, n*3*2);
- break;
- case MBell:
- break;
- case MSCut:
- vncrdbytes(v, junk, 3);
- n = vncrdlong(v);
- writesnarf(v, n);
- break;
- }
- }
- }
|