📄 vncs.c
字号:
v->dim = (Point){Dx(gscreen->r), Dy(gscreen->r)}; vncwrpoint(v, v->dim); if(verbose) fprint(2, "%V: send screen size %P (rect %R)\n", v, v->dim, gscreen->r); v->bpp = gscreen->depth; v->depth = gscreen->depth; v->truecolor = 1; v->bigendian = 0; chan2fmt(v, gscreen->chan); if(verbose) fprint(2, "%V: bpp=%d, depth=%d, chan=%s\n", v, v->bpp, v->depth, chantostr(buf, gscreen->chan)); vncwrpixfmt(v, v); vncwrlong(v, 14); vncwrbytes(v, "Plan9 Desktop", 14); vncflush(v); if(verbose) fprint(2, "%V: handshaking done\n", v); switch(rfork(RFPROC|RFMEM)){ case -1: fprint(2, "%V: cannot fork: %r; hanging up\n", v); vnchungup(v); default: clientreadproc(v); exits(nil); case 0: *vncpriv = v; v->nproc++; if(atexit(exiting) == 0){ exiting(); fprint(2, "%V: could not register atexit handler: %r; hanging up\n", v); exits(nil); } clientwriteproc(v); exits(nil); }}static voidvncname(char *fmt, ...){ int fd; char name[64], buf[32]; va_list arg; va_start(arg, fmt); vsnprint(name, sizeof name, fmt, arg); va_end(arg); sprint(buf, "/proc/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, name, strlen(name)); close(fd); }}/* * Set the pixel format being sent. Can only happen once. * (Maybe a client would send this again if the screen changed * underneath it? If we want to support this we need a way to * make sure the current image is no longer in use, so we can free it. */static voidsetpixelfmt(Vncs *v){ ulong chan; vncgobble(v, 3); v->Pixfmt = vncrdpixfmt(v); chan = fmt2chan(v); if(chan == 0){ fprint(2, "%V: bad pixel format; hanging up\n", v); vnchungup(v); } v->imagechan = chan;}/* * Set the preferred encoding list. Can only happen once. * If we want to support changing this more than once then * we need to put a lock around the encoding functions * so as not to conflict with updateimage. */static voidsetencoding(Vncs *v){ int n, x; vncrdchar(v); n = vncrdshort(v); while(n-- > 0){ x = vncrdlong(v); switch(x){ case EncCopyRect: v->copyrect = 1; continue; case EncMouseWarp: v->canwarp = 1; continue; } if(v->countrect != nil) continue; switch(x){ case EncRaw: v->encname = "raw"; v->countrect = countraw; v->sendrect = sendraw; break; case EncRre: v->encname = "rre"; v->countrect = countrre; v->sendrect = sendrre; break; case EncCorre: v->encname = "corre"; v->countrect = countcorre; v->sendrect = sendcorre; break; case EncHextile: v->encname = "hextile"; v->countrect = counthextile; v->sendrect = sendhextile; break; } } if(v->countrect == nil){ v->encname = "raw"; v->countrect = countraw; v->sendrect = sendraw; } if(verbose) fprint(2, "Encoding with %s%s%s\n", v->encname, v->copyrect ? ", copyrect" : "", v->canwarp ? ", canwarp" : "");}/* * Continually read updates from one client. */static voidclientreadproc(Vncs *v){ int incremental, key, keydown, buttons, type, x, y, n; char *buf; Rectangle r; vncname("read %V", v); for(;;){ type = vncrdchar(v); switch(type){ default: fprint(2, "%V: unknown vnc message type %d; hanging up\n", v, type); vnchungup(v); /* set pixel format */ case MPixFmt: setpixelfmt(v); break; /* ignore color map changes */ case MFixCmap: vncgobble(v, 3); n = vncrdshort(v); vncgobble(v, n*6); break; /* set encoding list */ case MSetEnc: setencoding(v); break; /* request image update in rectangle */ case MFrameReq: incremental = vncrdchar(v); r = vncrdrect(v); if(incremental){ vnclock(v); v->updaterequest = 1; vncunlock(v); }else{ drawlock(); /* protects rlist */ vnclock(v); /* protects updaterequest */ v->updaterequest = 1; addtorlist(&v->rlist, r); vncunlock(v); drawunlock(); } break; /* send keystroke */ case MKey: keydown = vncrdchar(v); vncgobble(v, 2); key = vncrdlong(v); vncputc(!keydown, key); break; /* send mouse event */ case MMouse: buttons = vncrdchar(v); x = vncrdshort(v); y = vncrdshort(v); mousetrack(x, y, buttons, nsec()/(1000*1000LL)); break; /* send cut text */ case MCCut: vncgobble(v, 3); n = vncrdlong(v); buf = malloc(n+1); if(buf){ vncrdbytes(v, buf, n); buf[n] = 0; vnclock(v); /* for snarfvers */ setsnarf(buf, n, &v->snarfvers); vncunlock(v); }else vncgobble(v, n); break; } }}static intnbits(ulong mask){ int n; n = 0; for(; mask; mask>>=1) n += mask&1; return n;}typedef struct Col Col;struct Col { int type; int nbits; int shift;};static ulongfmt2chan(Pixfmt *fmt){ Col c[4], t; int i, j, depth, n, nc; ulong mask, u; /* unpack the Pixfmt channels */ c[0] = (Col){CRed, nbits(fmt->red.max), fmt->red.shift}; c[1] = (Col){CGreen, nbits(fmt->green.max), fmt->green.shift}; c[2] = (Col){CBlue, nbits(fmt->blue.max), fmt->blue.shift}; nc = 3; /* add an ignore channel if necessary */ depth = c[0].nbits+c[1].nbits+c[2].nbits; if(fmt->bpp != depth){ /* BUG: assumes only one run of ignored bits */ if(fmt->bpp == 32) mask = ~0; else mask = (1<<fmt->bpp)-1; mask ^= fmt->red.max << fmt->red.shift; mask ^= fmt->green.max << fmt->green.shift; mask ^= fmt->blue.max << fmt->blue.shift; if(mask == 0) abort(); n = 0; for(; !(mask&1); mask>>=1) n++; c[3] = (Col){CIgnore, nbits(mask), n}; nc++; } /* sort the channels, largest shift (leftmost bits) first */ for(i=1; i<nc; i++) for(j=i; j>0; j--) if(c[j].shift > c[j-1].shift){ t = c[j]; c[j] = c[j-1]; c[j-1] = t; } /* build the channel descriptor */ u = 0; for(i=0; i<nc; i++){ u <<= 8; u |= CHAN1(c[i].type, c[i].nbits); } return u;}static voidchan2fmt(Pixfmt *fmt, ulong chan){ ulong c, rc, shift; shift = 0; for(rc = chan; rc; rc >>=8){ c = rc & 0xFF; switch(TYPE(c)){ case CRed: fmt->red = (Colorfmt){(1<<NBITS(c))-1, shift}; break; case CBlue: fmt->blue = (Colorfmt){(1<<NBITS(c))-1, shift}; break; case CGreen: fmt->green = (Colorfmt){(1<<NBITS(c))-1, shift}; break; } shift += NBITS(c); }}/* * Note that r has changed on the screen. * Updating the rlists is okay because they are protected by drawlock. */voidflushmemscreen(Rectangle r){ Vncs *v; if(!rectclip(&r, gscreen->r)) return; qlock(&clients); for(v=clients.head; v; v=v->next) addtorlist(&v->rlist, r); qunlock(&clients);}/* * Queue a mouse warp note for the next update to each client. */voidmousewarpnote(Point p){ Vncs *v; qlock(&clients); for(v=clients.head; v; v=v->next){ if(v->canwarp){ vnclock(v); v->needwarp = 1; v->warppt = p; vncunlock(v); } } qunlock(&clients);}/* * Send a client his changed screen image. * v is locked on entrance, locked on exit, but released during. */static intupdateimage(Vncs *v){ int i, ncount, nsend, docursor, needwarp; vlong ooffset; Point warppt; Rectangle cr; Rlist rlist; vlong t1; int (*count)(Vncs*, Rectangle); int (*send)(Vncs*, Rectangle); if(v->image == nil) return 0; /* warping info and unlock v so that updates can proceed */ needwarp = v->canwarp && v->needwarp; warppt = v->warppt; v->needwarp = 0; vncunlock(v); /* copy the screen bits and then unlock the screen so updates can proceed */ drawlock(); rlist = v->rlist; memset(&v->rlist, 0, sizeof v->rlist); /* if the cursor has moved or changed shape, we need to redraw its square */ lock(&cursor); if(v->cursorver != cursorver || !eqpt(v->cursorpos, cursorpos)){ docursor = 1; v->cursorver = cursorver; v->cursorpos = cursorpos; cr = cursorrect(); }else{ docursor = 0; cr = v->cursorr; } unlock(&cursor); if(docursor){ addtorlist(&rlist, v->cursorr); if(!rectclip(&cr, gscreen->r)) cr.max = cr.min; addtorlist(&rlist, cr); } /* copy changed screen parts, also check for parts overlapping cursor location */ for(i=0; i<rlist.nrect; i++){ if(!docursor) docursor = rectXrect(v->cursorr, rlist.rect[i]); memimagedraw(v->image, rlist.rect[i], gscreen, rlist.rect[i].min, memopaque, ZP, S); } if(docursor){ cursordraw(v->image, cr); addtorlist(&rlist, v->cursorr); v->cursorr = cr; } drawunlock(); ooffset = Boffset(&v->out); /* no more locks are held; talk to the client */ if(rlist.nrect == 0 && needwarp == 0){ vnclock(v); return 0; } count = v->countrect; send = v->sendrect; if(count == nil || send == nil){ count = countraw; send = sendraw; } ncount = 0; for(i=0; i<rlist.nrect; i++) ncount += (*count)(v, rlist.rect[i]); if(verbose > 1) fprint(2, "sendupdate: rlist.nrect=%d, ncount=%d", rlist.nrect, ncount); t1 = nsec(); vncwrchar(v, MFrameUpdate); vncwrchar(v, 0); vncwrshort(v, ncount+needwarp); nsend = 0; for(i=0; i<rlist.nrect; i++) nsend += (*send)(v, rlist.rect[i]); if(ncount != nsend){ fprint(2, "%V: ncount=%d, nsend=%d; hanging up\n", v, ncount, nsend); vnchungup(v); } if(needwarp){ vncwrrect(v, Rect(warppt.x, warppt.y, warppt.x+1, warppt.y+1)); vncwrlong(v, EncMouseWarp); } t1 = nsec() - t1; if(verbose > 1) fprint(2, " in %lldms, %lld bytes\n", t1/1000000, Boffset(&v->out) - ooffset); freerlist(&rlist); vnclock(v); return 1;}/* * Update the snarf buffer if it has changed. */static voidupdatesnarf(Vncs *v){ char *buf; int len; if(v->snarfvers == snarf.vers) return; vncunlock(v); qlock(&snarf); len = snarf.n; buf = malloc(len); if(buf == nil){ qunlock(&snarf); vnclock(v); return; } memmove(buf, snarf.buf, len); v->snarfvers = snarf.vers; qunlock(&snarf); vncwrchar(v, MSCut); vncwrbytes(v, "pad", 3); vncwrlong(v, len); vncwrbytes(v, buf, len); free(buf); vnclock(v);}/* * Continually update one client. */static voidclientwriteproc(Vncs *v){ char buf[32], buf2[32]; int sent; vncname("write %V", v); for(;;){ vnclock(v); if(v->ndead) break; if((v->image == nil && v->imagechan!=0) || (v->image && v->image->chan != v->imagechan)){ if(v->image) freememimage(v->image); v->image = allocmemimage(Rpt(ZP, v->dim), v->imagechan); if(v->image == nil){ fprint(2, "%V: allocmemimage: %r; hanging up\n", v); vnchungup(v); } if(verbose) fprint(2, "%V: translating image from chan=%s to chan=%s\n", v, chantostr(buf, gscreen->chan), chantostr(buf2, v->imagechan)); } sent = 0; if(v->updaterequest){ v->updaterequest = 0; updatesnarf(v); sent = updateimage(v); if(!sent) v->updaterequest = 1; } vncunlock(v); vncflush(v); if(!sent) sleep(sleeptime); } vncunlock(v); vnchungup(v);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -