#include "vnc.h" #include "vncv.h" #include typedef struct Cursor Cursor; typedef struct Mouse Mouse; struct Mouse { int buttons; Point xy; }; static void resize(Vnc *v, int first) { int fd; Point d; d = addpt(v->dim, Pt(2*Borderwidth, 2*Borderwidth)); lockdisplay(display); if(getwindow(display, Refnone) < 0) sysfatal("internal error: can't get the window image"); /* * limit the window to at most the vnc server's size */ if(first || d.x < Dx(screen->r) || d.y < Dy(screen->r)){ fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", d.x, d.y); close(fd); } } unlockdisplay(display); } static void eresized(void) { resize(vnc, 0); requestupdate(vnc, 0); } static Cursor dotcursor = { {-7, -7}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } }; static void mouseevent(Vnc *v, Mouse m) { vnclock(v); vncwrchar(v, MMouse); vncwrchar(v, m.buttons); vncwrpoint(v, m.xy); vncflush(v); vncunlock(v); } void mousewarp(Point pt) { pt = addpt(pt, screen->r.min); if(fprint(mousefd, "m%d %d", pt.x, pt.y) < 0) fprint(2, "mousefd write: %r\n"); } void initmouse(void) { char buf[1024]; snprint(buf, sizeof buf, "%s/mouse", display->devdir); if((mousefd = open(buf, ORDWR)) < 0) sysfatal("open %s: %r", buf); } enum { EventSize = 1+4*12 }; void readmouse(Vnc *v) { int cursorfd, len, n; char buf[10*EventSize], *start, *end; uchar curs[2*4+2*2*16]; Cursor *cs; Mouse m; cs = &dotcursor; snprint(buf, sizeof buf, "%s/cursor", display->devdir); if((cursorfd = open(buf, OWRITE)) < 0) sysfatal("open %s: %r", buf); BPLONG(curs+0*4, cs->offset.x); BPLONG(curs+1*4, cs->offset.y); memmove(curs+2*4, cs->clr, 2*2*16); write(cursorfd, curs, sizeof curs); resize(v, 1); requestupdate(vnc, 0); start = end = buf; len = 0; for(;;){ if((n = read(mousefd, end, sizeof(buf) - (end - buf))) < 0) sysfatal("read mouse failed"); len += n; end += n; while(len >= EventSize){ if(*start == 'm'){ m.xy.x = atoi(start+1); m.xy.y = atoi(start+1+12); m.buttons = atoi(start+1+2*12) & 0x1F; m.xy = subpt(m.xy, screen->r.min); if(ptinrect(m.xy, Rpt(ZP, v->dim))){ mouseevent(v, m); /* send wheel button *release* */ if ((m.buttons & 0x7) != m.buttons) { m.buttons &= 0x7; mouseevent(v, m); } } } else eresized(); start += EventSize; len -= EventSize; } if(start - buf > sizeof(buf) - EventSize){ memmove(buf, start, len); start = buf; end = start+len; } } } static int tcs(int fd0, int fd1) { int pfd[2]; if(strcmp(charset, "utf-8") == 0) goto Dup; if(pipe(pfd) < 0) goto Dup; switch(rfork(RFPROC|RFFDG|RFMEM)){ case -1: close(pfd[0]); close(pfd[1]); goto Dup; case 0: if(fd0 < 0){ dup(pfd[0], 0); dup(fd1, 1); close(fd1); } else { dup(pfd[0], 1); dup(fd0, 0); close(fd0); } close(pfd[0]); close(pfd[1]); execl("/bin/tcs", "tcs", fd0 < 0 ? "-f" : "-t", charset, 0); execl("/bin/cat", "cat", 0); _exits(0); } close(pfd[0]); return pfd[1]; Dup: return dup(fd0 < 0 ? fd1 : fd0, -1); } static int snarffd = -1; static ulong snarfvers; static int gotsnarf(void) { Dir *dir; int ret; if(snarffd < 0 || (dir = dirfstat(snarffd)) == nil) return 0; ret = dir->qid.vers != snarfvers; snarfvers = dir->qid.vers; free(dir); return ret; } void writesnarf(Vnc *v, long n) { uchar buf[8192]; int fd, sfd; long m; vnclock(v); fd = -1; if((sfd = create("/dev/snarf", OWRITE, 0666)) >= 0){ fd = tcs(-1, sfd); close(sfd); } if(fd < 0) vncgobble(v, n); else { while(n > 0){ m = n; if(m > sizeof(buf)) m = sizeof(buf); vncrdbytes(v, buf, m); n -= m; write(fd, buf, m); } close(fd); waitpid(); } gotsnarf(); vncunlock(v); } char * getsnarf(int *sz) { char *snarf, *p; int fd, n, c; *sz =0; n = 8192; p = snarf = malloc(n); seek(snarffd, 0, 0); if((fd = tcs(snarffd, -1)) >= 0){ while((c = read(fd, p, n)) > 0){ p += c; n -= c; *sz += c; if (n == 0){ snarf = realloc(snarf, *sz + 8192); n = 8192; } } close(fd); waitpid(); } return snarf; } void checksnarf(Vnc *v) { char *snarf; int len; if(snarffd < 0){ snarffd = open("/dev/snarf", OREAD); if(snarffd < 0) sysfatal("can't open /dev/snarf: %r"); } for(;;){ sleep(1000); vnclock(v); if(gotsnarf()){ snarf = getsnarf(&len); vncwrchar(v, MCCut); vncwrbytes(v, "pad", 3); vncwrlong(v, len); vncwrbytes(v, snarf, len); vncflush(v); free(snarf); } vncunlock(v); } }