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; } } }
int unloadimage(Image *i, Rectangle r, uchar *data, int ndata) { int bpl, n, chunk, dx, dy; uchar *a, *start; Display *d; if(!rectinrect(r, i->r)) { werrstr("unloadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); if(ndata < bpl*Dy(r)) { werrstr("unloadimage: buffer too small"); return -1; } start = data; d = i->display; chunk = d->bufsize; flushimage(d, 0); /* make sure subsequent flush is for us only */ while(r.min.y < r.max.y) { dx = Dx(r); dy = chunk/bpl; if(dy <= 0) { dy = 1; dx = ((chunk*dx)/bpl) & ~7; n = bytesperline(Rect(r.min.x, r.min.y, r.min.x+dx, r.min.y+dy), i->depth); if(unloadimage(i, Rect(r.min.x+dx, r.min.y, r.max.x, r.min.y+dy), data+n, bpl-n) < 0) return -1; } else { if(dy > Dy(r)) dy = Dy(r); n = bpl*dy; } a = bufimage(d, 1+4+4*4); if(a == nil) { werrstr("unloadimage: %r"); return -1; } a[0] = 'r'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.min.x+dx); BPLONG(a+17, r.min.y+dy); if(flushimage(d, 0) < 0) return -1; if(read(d->fd, data, n) < 0) return -1; data += bpl*dy; r.min.y += dy; } return data - start; }
void esetcursor(Cursor *c) { uchar curs[2*4+2*2*16]; if(c == 0) write(cursorfd, curs, 0); else{ BPLONG(curs+0*4, c->offset.x); BPLONG(curs+1*4, c->offset.y); memmove(curs+2*4, c->clr, 2*2*16); write(cursorfd, curs, sizeof curs); } }
void setcursor(Mousectl *mc, Cursor *c) { char curs[2*4+2*2*16]; if(c == nil) write(mc->cfd, curs, 0); else{ BPLONG(curs+0*4, c->offset.x); BPLONG(curs+1*4, c->offset.y); memmove(curs+2*4, c->clr, 2*2*16); write(mc->cfd, curs, sizeof curs); } }
int loadimage(Image *i, Rectangle r, uchar *data, int ndata) { long dy; int n, bpl; uchar *a; int chunk; chunk = i->display->bufsize - 64; if(!rectinrect(r, i->r)){ werrstr("loadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); n = bpl*Dy(r); if(n > ndata){ werrstr("loadimage: insufficient data"); return -1; } ndata = 0; while(r.max.y > r.min.y){ dy = r.max.y - r.min.y; if(dy*bpl > chunk) dy = chunk/bpl; if(dy <= 0){ werrstr("loadimage: image too wide for buffer"); return -1; } n = dy*bpl; a = bufimage(i->display, 21+n); if(a == nil){ werrstr("bufimage failed"); return -1; } a[0] = 'y'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.max.x); BPLONG(a+17, r.min.y+dy); memmove(a+21, data, n); ndata += n; data += n; r.min.y += dy; } if(flushimage(i->display, 0) < 0) return -1; return ndata; }
int unloadimage(Image *i, Rectangle r, uchar *data, int ndata) { int bpl, n, ntot, dy; uchar *a; Display *d; if(!rectinrect(r, i->r)){ werrstr("unloadimage: bad rectangle"); return -1; } bpl = bytesperline(r, i->depth); if(ndata < bpl*Dy(r)){ werrstr("unloadimage: buffer too small"); return -1; } d = i->display; flushimage(d, 0); /* make sure subsequent flush is for us only */ ntot = 0; while(r.min.y < r.max.y){ a = bufimage(d, 1+4+4*4); if(a == 0){ werrstr("unloadimage: %r"); return -1; } dy = 8000/bpl; if(dy <= 0){ werrstr("unloadimage: image too wide"); return -1; } if(dy > Dy(r)) dy = Dy(r); a[0] = 'r'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, r.min.y); BPLONG(a+13, r.max.x); BPLONG(a+17, r.min.y+dy); if(flushimage(d, 0) < 0) return -1; n = read(d->fd, data+ntot, ndata-ntot); if(n < 0) return n; ntot += n; r.min.y += dy; } return ntot; }
int cloadimage(Image *i, Rectangle r, uchar *data, int ndata) { int m, nb, miny, maxy, ncblock; uchar *a; if(!rectinrect(r, i->r)){ werrstr("cloadimage: bad rectangle"); return -1; } miny = r.min.y; m = 0; ncblock = _compblocksize(r, i->depth); while(miny != r.max.y){ maxy = atoi((char*)data+0*12); nb = atoi((char*)data+1*12); if(maxy<=miny || r.max.y<maxy){ werrstr("creadimage: bad maxy %d", maxy); return -1; } data += 2*12; ndata -= 2*12; m += 2*12; if(nb<=0 || ncblock<nb || nb>ndata){ werrstr("creadimage: bad count %d", nb); return -1; } a = bufimage(i->display, 21+nb); if(a == nil) return -1; a[0] = 'Y'; BPLONG(a+1, i->id); BPLONG(a+5, r.min.x); BPLONG(a+9, miny); BPLONG(a+13, r.max.x); BPLONG(a+17, maxy); memmove(a+21, data, nb); miny = maxy; data += nb; ndata += nb; m += nb; } return m; }
int flushimage(Display *d, int visible) { if(d == nil) return 0; if(visible){ *d->bufp++ = 'v'; /* five bytes always reserved for this */ if(d->_isnewdisplay){ BPLONG(d->bufp, d->screenimage->id); d->bufp += 4; } } return doflush(d); }
int nameimage(Image *i, char *name, int in) { uchar *a; int n; n = strlen(name); a = bufimage(i->display, 1+4+1+1+n); if(a == 0) return 0; a[0] = 'N'; BPLONG(a+1, i->id); a[5] = in; a[6] = n; memmove(a+7, name, n); if(flushimage(i->display, 0) < 0) return 0; return 1; }
static void dopoly(int cmd, Image *dst, Point *pp, int np, int end0, int end1, int radius, Image *src, Point *sp, Drawop op) { uchar *a, *t, *u; int i, ox, oy; if(np == 0) return; t = malloc(np*2*3); if(t == nil) return; u = t; ox = oy = 0; for(i=0; i<np; i++){ u = addcoord(u, ox, pp[i].x); ox = pp[i].x; u = addcoord(u, oy, pp[i].y); oy = pp[i].y; } _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t)); if(a == 0){ free(t); fprint(2, "image poly: %r\n"); return; } a[0] = cmd; BPLONG(a+1, dst->id); BPSHORT(a+5, np-1); BPLONG(a+7, end0); BPLONG(a+11, end1); BPLONG(a+15, radius); BPLONG(a+19, src->id); BPLONG(a+23, sp->x); BPLONG(a+27, sp->y); memmove(a+31, t, u-t); free(t); }
int _freeimage1(Image *i) { uchar *a; Display *d; Image *w; if(i == 0) return 0; /* make sure no refresh events occur on this if we block in the write */ d = i->display; /* flush pending data so we don't get error deleting the image */ flushimage(d, 0); a = bufimage(d, 1+4); if(a == 0) return -1; a[0] = 'f'; BPLONG(a+1, i->id); if(i->screen){ w = d->windows; if(w == i) d->windows = i->next; else while(w){ if(w->next == i){ w->next = i->next; break; } w = w->next; } } if(flushimage(d, i->screen!=0) < 0) return -1; return 0; }
Point _string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, int len, Rectangle clipr, Image *bg, Point bgp, Drawop op) { int m, n, wid, max; ushort cbuf[Max], *c, *ec; uchar *b; char *subfontname; char **sptr; Rune **rptr; Font *def; Subfont *sf; if(s == nil){ s = ""; sptr = nil; }else sptr = &s; if(r == nil){ r = (Rune*) L""; rptr = nil; }else rptr = &r; sf = nil; while((*s || *r) && len > 0){ max = Max; if(len < max) max = len; n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname); if(n > 0){ _setdrawop(dst->display, op); m = 47+2*n; if(bg) m += 4+2*4; b = bufimage(dst->display, m); if(b == 0){ fprint(2, "string: %r\n"); break; } if(bg) b[0] = 'x'; else b[0] = 's'; BPLONG(b+1, dst->id); BPLONG(b+5, src->id); BPLONG(b+9, f->cacheimage->id); BPLONG(b+13, pt.x); BPLONG(b+17, pt.y+f->ascent); BPLONG(b+21, clipr.min.x); BPLONG(b+25, clipr.min.y); BPLONG(b+29, clipr.max.x); BPLONG(b+33, clipr.max.y); BPLONG(b+37, sp.x); BPLONG(b+41, sp.y); BPSHORT(b+45, n); b += 47; if(bg){ BPLONG(b, bg->id); BPLONG(b+4, bgp.x); BPLONG(b+8, bgp.y); b += 12; } ec = &cbuf[n]; for(c=cbuf; c<ec; c++, b+=2) BPSHORT(b, *c); pt.x += wid; bgp.x += wid; agefont(f); len -= n; } if(subfontname){ freesubfont(sf); if((sf=_getsubfont(f->display, subfontname)) == 0){ def = f->display ? f->display->defaultfont : nil; if(def && f!=def) f = def; else break; } /* * must not free sf until cachechars has found it in the cache * and picked up its own reference. */ } } return pt; }
static void doellipse(int cmd, Image *dst, Point *c, int xr, int yr, int thick, Image *src, Point *sp, int alpha, int phi, Drawop op) { uchar *a; _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4); if(a == 0) { fprint(2, "image ellipse: %r\n"); return; } a[0] = cmd; BPLONG(a+1, dst->id); BPLONG(a+5, src->id); BPLONG(a+9, c->x); BPLONG(a+13, c->y); BPLONG(a+17, xr); BPLONG(a+21, yr); BPLONG(a+25, thick); BPLONG(a+29, sp->x); BPLONG(a+33, sp->y); BPLONG(a+37, alpha); BPLONG(a+41, phi); }
static void draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op) { uchar *a; _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4); if(a == nil) return; if(src == nil) src = dst->display->black; if(mask == nil) mask = dst->display->opaque; a[0] = 'd'; BPLONG(a+1, dst->id); BPLONG(a+5, src->id); BPLONG(a+9, mask->id); BPLONG(a+13, r->min.x); BPLONG(a+17, r->min.y); BPLONG(a+21, r->max.x); BPLONG(a+25, r->max.y); BPLONG(a+29, p0->x); BPLONG(a+33, p0->y); BPLONG(a+37, p1->x); BPLONG(a+41, p1->y); }
Image* namedimage(Display *d, char *name) { uchar *a; char *err, buf[12*12+1]; Image *i; int id, n; ulong chan; err = 0; i = 0; n = strlen(name); if(n >= 256){ err = "name too long"; Error: if(err) werrstr("namedimage: %s", err); else werrstr("namedimage: %r"); if(i) free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+1+n); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'n'; BPLONG(a+1, id); a[5] = n; memmove(a+6, name, n); if(flushimage(d, 0) < 0) goto Error; if(pread(d->ctlfd, buf, sizeof buf, 0) < 12*12) goto Error; buf[12*12] = '\0'; i = malloc(sizeof(Image)); if(i == nil){ Error1: a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } i->display = d; i->id = id; if((chan=strtochan(buf+2*12))==0){ werrstr("bad channel '%.12s' from devdraw", buf+2*12); goto Error1; } i->chan = chan; i->depth = chantodepth(chan); i->repl = atoi(buf+3*12); i->r.min.x = atoi(buf+4*12); i->r.min.y = atoi(buf+5*12); i->r.max.x = atoi(buf+6*12); i->r.max.y = atoi(buf+7*12); i->clipr.min.x = atoi(buf+8*12); i->clipr.min.y = atoi(buf+9*12); i->clipr.max.x = atoi(buf+10*12); i->clipr.max.y = atoi(buf+11*12); i->screen = 0; i->next = 0; return i; }
void lineop(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp, Drawop op) { uchar *a; _setdrawop(dst->display, op); a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4); if(a == 0){ fprint(2, "image line: %r\n"); return; } a[0] = 'L'; BPLONG(a+1, dst->id); BPLONG(a+5, p0.x); BPLONG(a+9, p0.y); BPLONG(a+13, p1.x); BPLONG(a+17, p1.y); BPLONG(a+21, end0); BPLONG(a+25, end1); BPLONG(a+29, radius); BPLONG(a+33, src->id); BPLONG(a+37, sp.x); BPLONG(a+41, sp.y); }
Image* _allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh) { uchar *a; char *err; Image *i; Rectangle clipr; int id; int depth; err = 0; i = 0; if(chan == 0){ werrstr("bad channel descriptor"); return nil; } depth = chantodepth(chan); if(depth == 0){ err = "bad channel descriptor"; Error: if(err) werrstr("allocimage: %s", err); else werrstr("allocimage: %r"); free(i); return 0; } /* flush pending data so we don't get error allocating the image */ flushimage(d, 0); a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4); if(a == 0) goto Error; d->imageid++; id = d->imageid; a[0] = 'b'; BPLONG(a+1, id); BPLONG(a+5, screenid); a[9] = refresh; BPLONG(a+10, chan); a[14] = repl; BPLONG(a+15, r.min.x); BPLONG(a+19, r.min.y); BPLONG(a+23, r.max.x); BPLONG(a+27, r.max.y); if(repl) /* huge but not infinite, so various offsets will leave it huge, not overflow */ clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF); else clipr = r; BPLONG(a+31, clipr.min.x); BPLONG(a+35, clipr.min.y); BPLONG(a+39, clipr.max.x); BPLONG(a+43, clipr.max.y); BPLONG(a+47, val); if(flushimage(d, 0) < 0) goto Error; if(ai) i = ai; else{ i = malloc(sizeof(Image)); if(i == nil){ a = bufimage(d, 1+4); if(a){ a[0] = 'f'; BPLONG(a+1, id); flushimage(d, 0); } goto Error; } } i->display = d; i->id = id; i->depth = depth; i->chan = chan; i->r = r; i->clipr = clipr; i->repl = repl; i->screen = 0; i->next = 0; return i; }
static long mouseread(Chan *c, void *va, long n, vlong off) { char buf[1+4*12+1], *s; uchar *p; ulong offset = off; Mousestate m; int b; p = va; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen); case Qcursor: if(offset != 0) return 0; if(n < 2*4+2*2*16) error(Eshort); n = 2*4+2*2*16; lock(&cursor.lk); BPLONG(p+0, curs.offset.x); BPLONG(p+4, curs.offset.y); memmove(p+8, curs.clr, 2*16); memmove(p+40, curs.set, 2*16); unlock(&cursor.lk); return n; case Qmouse: while(mousechanged(0) == 0) sleep(&mouse.r, mousechanged, 0); mouse.qfull = 0; mousetime = seconds(); /* * No lock of the indices is necessary here, because ri is only * updated by us, and there is only one mouse reader * at a time. I suppose that more than one process * could try to read the fd at one time, but such behavior * is degenerate and already violates the calling * conventions for sleep above. */ if(mouse.ri != mouse.wi) { m = mouse.queue[mouse.ri]; if(++mouse.ri == nelem(mouse.queue)) mouse.ri = 0; } else { while(!canlock(&cursor.lk)) tsleep(&up->sleep, return0, 0, TK2MS(1)); m = mouse.mstate; unlock(&cursor.lk); } b = buttonmap[m.buttons&7]; /* put buttons 4 and 5 back in */ b |= m.buttons & (3<<3); if (scrollswap){ if (b == 8) b = 16; else if (b == 16) b = 8; } sprint(buf, "m%11d %11d %11d %11lud ", m.xy.x, m.xy.y, b, m.msec); mouse.lastcounter = m.counter; if(n > 1+4*12) n = 1+4*12; if(mouse.lastresize != mouse.resize){ mouse.lastresize = mouse.resize; buf[0] = 'r'; } memmove(va, buf, n); return n; case Qsnarf: if(offset == 0){ s = getsnarf(); if(c->aux) free(c->aux); c->aux = s; } if(c->aux == nil) return 0; return readstr(offset, va, n, c->aux); } return 0; }