- use the double-buffer buffer to allow redrawing on resize events. specifing -d on the command line now only disables synchronous drawing events. - use threaded mouse and keyboard to allow for asynchronous receoption of quit messages. this allows plot to exit before drawing is completed. for programs like mapdemo, this is important. there were two things that needed to get fixed as a result - replace fprint(2, ...); exits("bad"); with sysfatal. also get rid of stdio. - dpoint needed a mach-dependentent (sic) version. otherwise points on a resized screen will not be properly placed. Notes: Sun Feb 23 02:25:46 EST 2014 geoff wow, lots of changes. Reference: /n/sources/patch/plot-resize Date: Mon Apr 22 06:17:03 CES 2013 Signed-off-by: quanstro@quanstro.net Reviewed-by: quanstro --- /sys/src/cmd/plot/plot.c Mon Apr 22 06:12:11 2013 +++ /sys/src/cmd/plot/plot.c Mon Apr 22 06:12:09 2013 @@ -3,7 +3,9 @@ #include #include "plot.h" #include -#include +#include +#include +#include void define(char*); void call(char*); @@ -106,6 +108,7 @@ #define NFSTACK 50 struct fstack{ + char name[128]; int peekc; int lineno; char *corebuf; @@ -124,37 +127,123 @@ int cnt[NPTS]; /* control-polygon vertex counts */ double *pts[NPTS]; /* control-polygon vertex pointers */ -void eresized(int new){ - if(new && getwindow(display, Refnone) < 0){ - fprint(2, "Can't reattach to window: %r\n"); - exits("resize"); +extern void m_swapbuf(void); /* reaching into implementation. ick. */ +extern Image *offscreen; + +void +resize(Point p) +{ + int fd; + + fd = open("/dev/wctl", OWRITE); + if(fd >= 0){ + fprint(fd, "resize -dx %d -dy %d", p.x+4*2, p.y+4*2); + close(fd); } } + +void +resizeto(Point p) +{ + Point s; + + s = (Point){Dx(screen->r), Dy(screen->r)}; + if(eqpt(p, s)) + return; + resize(p); +} + +void +eresized(int new) +{ + if(new && getwindow(display, Refnone) < 0) + sysfatal("plot: can't reattach to window: %r\n"); +// resizeto((Point){Dx(offscreen->r)+4, Dy(offscreen->r)+4}); + m_swapbuf(); +} + char *items[]={ "exit", 0 }; Menu menu={items}; + void -main(int arc, char *arv[]){ +mouseproc(void*) +{ + void *v; + Rune r; + Alt alts[4]; + Keyboardctl *k; + Mousectl *m; + Mouse mc; + enum{Amouse, Akbd, Aresize, Aend}; + + m = initmouse(nil, screen); + k = initkeyboard(nil); + + memset(alts, 0, sizeof alts); + alts[Amouse].c = m->c; + alts[Amouse].v = &mc; + alts[Amouse].op = CHANRCV; + + alts[Akbd].c = k->c; + alts[Akbd].v = &r; + alts[Akbd].op = CHANRCV; + + alts[Aresize].c = m->resizec; + alts[Aresize].v = &v; + alts[Aresize].op = CHANRCV; + + alts[Aend].op = CHANEND; + + for(;;) + switch(alt(alts)){ + default: + sysfatal("mouse!"); + case Amouse: + if(mc.buttons & 4) { + if(menuhit(3, m, &menu, nil) == 0) + threadexitsall(""); + } + break; + case Akbd: + switch(r){ + case 'q': + case 0x7f: + case 0x04: + threadexitsall(""); + } + break; + case Aresize: + eresized(1); + ; + } +} + +void +threadmain(int arc, char *arv[]){ char *ap; Biobuf *bp; int fd; int i; int dflag; char *oflag; - Mouse m; + bp = 0; fd = dup(0, -1); /* because openpl will close 0! */ dflag=0; oflag=""; + argv0 = arv[0]; for(i=1;i!=arc;i++) if(arv[i][0]=='-') switch(arv[i][1]){ case 'd': dflag=1; break; case 'o': oflag=arv[i]+2; break; case 's': fd=server(); break; } openpl(oflag); - if(dflag) doublebuffer(); + proccreate(mouseproc, nil, 32*1024); + if(dflag) + doublebuffer(); for (; arc > 1; arc--, arv++) { if (arv[1][0] == '-') { ap = arv[1]; @@ -192,10 +281,8 @@ } closepl(); flushimage(display, 1); - for(;;){ - m=emouse(); - if(m.buttons&4 && emenuhit(3, &m, &menu)==0) exits(0); - } + for(;;) + sleep(1000); } int isalpha(int c) { @@ -320,10 +407,8 @@ c=nextc(); }while(strchr(" \t\n", c) || c!='.' && c!='+' && c!='-' && ispunct(c)); fsp->peekc=c; - if(!numstring()){ - fprint(2, "line %d: number expected\n", fsp->lineno); - exits("input error"); - } + if(!numstring()) + sysfatal("%s:%d: number expected\n", fsp->name, fsp->lineno); x[i]=atof(argstr)*fsp->scale; } } @@ -354,17 +439,11 @@ c=nextc(); if(c==r){ if(*cntp){ - if(*cntp&1){ - fprint(2, "line %d: phase error\n", - fsp->lineno); - exits("bad input"); - } + if(*cntp&1) + sysfatal("%s:%d: phase error", fsp->name, fsp->lineno); *cntp/=2; - if(ptsp==&pts[NPTS]){ - fprint(2, "line %d: out of polygons\n", - fsp->lineno); - exits("exceeded limit"); - } + if(ptsp==&pts[NPTS]) + sysfatal("%s:%d: out of polygons", fsp->name, fsp->lineno); *++ptsp=xp; *++cntp=0; } @@ -379,14 +458,10 @@ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': fsp->peekc=c; - if(!numstring()){ - fprint(2, "line %d: expected number\n", fsp->lineno); - exits("bad input"); - } - if(xp==&x[NX]){ - fprint(2, "line %d: out of space\n", fsp->lineno); - exits("exceeded limit"); - } + if(!numstring()) + sysfatal("%s:%d: expected number", fsp->name, fsp->lineno); + if(xp==&x[NX]) + sysfatal("%s:%d: out of space", fsp->name, fsp->lineno); *xp++=atof(argstr); ++*cntp; break; @@ -443,19 +518,14 @@ for(pplots=plots;pplots->cc;pplots++) if(strncmp(argstr, pplots->cc, pplots->numc)==0) break; - if(pplots->cc==0){ - fprint(2, "line %d, %s unknown\n", fsp->lineno, - argstr); - exits("bad command"); - } + if(pplots->cc==0) + sysfatal("%s:%d: %s unknown", fsp->name, fsp->lineno, argstr); } else{ fsp->peekc=c; } - if(!pplots){ - fprint(2, "line %d, no command!\n", fsp->lineno); - exits("no command"); - } + if(!pplots) + sysfatal("%s:%d: no command\n", fsp->name, fsp->lineno); switch(pplots-plots){ case ARC: numargs(7); rarc(x[0],x[1],x[2],x[3],x[4],x[5],x[6]); break; case BOX: numargs(4); box(x[0], x[1], x[2], x[3]); break; @@ -494,8 +564,7 @@ case TEXT: strarg(); text(argstr); pplots=0; break; case VEC: numargs(2); vec(x[0], x[1]); break; default: - fprint(2, "plot: missing case %ld\n", pplots-plots); - exits("internal error"); + sysfatal("%s:%d: plot: missing case %ld\n", fsp->name, fsp->lineno, pplots-plots); } } return 1; @@ -512,10 +581,8 @@ int curly = 0; ap = a; while(isalpha(*ap))ap++; - if(ap == a){ - fprint(2,"no name with define\n"); - exits("define"); - } + if(ap == a) + sysfatal("plot: no name with define\n"); i = ap - a; if(names+i+1 > enames){ names = malloc((unsigned)512); @@ -532,10 +599,8 @@ fptr->stash = nstash; while(*ap != '{') if(*ap == '\n'){ - if((ap=Brdline(fsp->fd, '\n'))==0){ - fprint(2,"unexpected end of file\n"); - exits("eof"); - } + if((ap=Brdline(fsp->fd, '\n'))==0) + sysfatal("plot: unexpected eof"); } else ap++; while((j=Bgetc(fsp->fd))!= Beof){ @@ -549,14 +614,14 @@ free(bstash); size += 1024; bstash = realloc(bstash,size); + if(bstash == nil) + sysfatal("plot: realloc: %r"); estash = bstash+size; } } *nstash++ = '\0'; - if(fptr++ >= &flibr[MAXL]){ - fprint(2,"Too many objects\n"); - exits("too many objects"); - } + if(fptr++ >= &flibr[MAXL]) + sysfatal("too many objects"); } void call(char *a){ char *ap; @@ -571,20 +636,17 @@ if (!(strcmp(a, f->name))) break; } - if(f == fptr){ - fprint(2, "object %s not defined\n",a); - exits("undefined"); - } + if(f == fptr) + sysfatal("plot: object %s not defined",a); *ap = sav; while (isspace(*ap) || *ap == ',') ap++; if (*ap != '\0') SC = atof(ap); else SC = 1.; - if(++fsp==&fstack[NFSTACK]){ - fprint(2, "input stack overflow\n"); - exits("blew stack"); - } + if(++fsp==&fstack[NFSTACK]) + sysfatal("plot: input stack overflow"); + snprint(fsp->name, sizeof fsp->name, "call %s", f->name); fsp->peekc=Beof; fsp->lineno=1; fsp->corebuf=f->stash; @@ -594,14 +656,11 @@ void include(char *a){ Biobuf *fd; fd=Bopen(a, OREAD); - if(fd==0){ - perror(a); - exits("can't include"); - } - if(++fsp==&fstack[NFSTACK]){ - fprint(2, "input stack overflow\n"); - exits("blew stack"); - } + if(fd==0) + sysfatal("plot: cant include %s: %r", a); + if(++fsp==&fstack[NFSTACK]) + sysfatal("plot: input stack overflow"); + snprint(fsp->name, sizeof fsp->name, "%s", a); fsp->peekc=Beof; fsp->lineno=1; fsp->corebuf=0; --- /sys/src/cmd/plot/libplot/pprompt.c Mon Apr 22 06:12:13 2013 +++ /sys/src/cmd/plot/libplot/pprompt.c Mon Apr 22 06:12:12 2013 @@ -1,5 +1,5 @@ #include "mplot.h" void pprompt(void){ - fprintf(stderr, ":"); + fprint(2, ":"); } --- /sys/src/cmd/plot/libplot/fill.c Mon Apr 22 06:12:16 2013 +++ /sys/src/cmd/plot/libplot/fill.c Mon Apr 22 06:12:14 2013 @@ -47,8 +47,7 @@ edges=(Edge *)malloc(nvert*sizeof(Edge)); if(edges==0){ NoSpace: - fprintf(stderr, "polygon: no space\n"); - exits("malloc failed"); + sysfatal("polygon: no space"); } ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *)); if(ylist==0) goto NoSpace; --- /sys/src/cmd/plot/libplot/ppause.c Mon Apr 22 06:12:18 2013 +++ /sys/src/cmd/plot/libplot/ppause.c Mon Apr 22 06:12:16 2013 @@ -1,7 +1,6 @@ #include "mplot.h" void ppause(void){ char aa[4]; - fflush(stdout); read(0, aa, 4); erase(); } --- /sys/src/cmd/plot/libplot/dpoint.c Mon Apr 22 06:12:20 2013 +++ /sys/src/cmd/plot/libplot/dpoint.c Mon Apr 22 06:12:19 2013 @@ -1,6 +1,5 @@ #include "mplot.h" void dpoint(double x, double y){ - draw(screen, Rect(SCX(x), SCY(y), SCX(x)+1, SCY(y)+1), getcolor(e1->foregr), - nil, ZP); + m_dpt(x, y); move(x, y); } --- /sys/src/cmd/plot/libplot/mplot.h Mon Apr 22 06:12:22 2013 +++ /sys/src/cmd/plot/libplot/mplot.h Mon Apr 22 06:12:21 2013 @@ -1,6 +1,6 @@ #include #include -#include +//#include #include #include #define SCX(A) ((((A) - e1->xmin)*e1->scalex + e1->left)+.5) @@ -39,6 +39,7 @@ void m_finish(void); void m_initialize(char *); int m_text(int, int, char *, char *, int, int, int); +void m_dpt(double, double); void m_vector(int, int, int, int, int); void m_swapbuf(void); void m_dblbuf(void); --- /sys/src/cmd/plot/libplot/machdep.c Mon Apr 22 06:12:24 2013 +++ /sys/src/cmd/plot/libplot/machdep.c Mon Apr 22 06:12:23 2013 @@ -1,114 +1,135 @@ #include "mplot.h" Image *offscreen; +static int buffer; + +static Point +xlp(Point p) +{ + p.x += screen->r.min.x + 4 - offscreen->r.min.x; + p.y += screen->r.min.y + 4 - offscreen->r.min.y; + return p; +} + +static Rectangle +xlr(Rectangle r) +{ + int dx, dy; + + dx = screen->r.min.x + 4 - offscreen->r.min.x; + dy = screen->r.min.y + 4 - offscreen->r.min.y; + r.min.x += dx; + r.min.y += dy; + r.max.x += dx; + r.max.y += dy; + return r; +} + /* * Clear the window from x0, y0 to x1, y1 (inclusive) to color c */ -void m_clrwin(int x0, int y0, int x1, int y1, int c){ +void +m_clrwin(int x0, int y0, int x1, int y1, int c) +{ draw(offscreen, Rect(x0, y0, x1+1, y1+1), getcolor(c), nil, ZP); + if(offscreen != screen && !buffer) + draw(screen, xlr(Rect(x0, y0, x1+1, y1+1)), getcolor(c), nil, ZP); } /* * Draw text between pointers p and q with first character centered at x, y. * Use color c. Centered if cen is non-zero, right-justified if right is non-zero. * Returns the y coordinate for any following line of text. */ -int m_text(int x, int y, char *p, char *q, int c, int cen, int right){ +int +m_text(int x, int y, char *p, char *q, int c, int cen, int right) +{ Point tsize; - USED(c); - tsize=stringsize(font, p); - if(cen) x -= tsize.x/2; - else if(right) x -= tsize.x; + + tsize = stringsize(font, p); + if(cen) + x -= tsize.x/2; + else if(right) + x -= tsize.x; stringn(offscreen, Pt(x, y-tsize.y/2), getcolor(c), ZP, font, p, q-p); + if(offscreen != screen && !buffer) + stringn(screen, xlp(Pt(x, y-tsize.y/2)), getcolor(c), ZP, font, p, q-p); return y+tsize.y; } /* + * draw point x, y + */ +void +m_dpt(double x, double y) +{ + Image *c; + + c = getcolor(e1->foregr); + draw(offscreen, Rect(SCX(x), SCY(y), SCX(x)+1, SCY(y)+1), c, nil, ZP); + if(offscreen != screen && !buffer) + draw(screen, xlr(Rect(SCX(x), SCY(y), SCX(x)+1, SCY(y)+1)), c, nil, ZP); +} + +/* * Draw the vector from x0, y0 to x1, y1 in color c. * Clipped by caller */ -void m_vector(int x0, int y0, int x1, int y1, int c){ +void +m_vector(int x0, int y0, int x1, int y1, int c) +{ line(offscreen, Pt(x0, y0), Pt(x1, y1), Endsquare, Endsquare, 0, getcolor(c), ZP); -} -char *scanint(char *s, int *n){ - while(*s<'0' || '9'<*s){ - if(*s=='\0'){ - fprint(2, "plot: bad -Wxmin,ymin,xmax,ymax\n"); - exits("bad arg"); - } - s++; - } - *n=0; - while('0'<=*s && *s<='9'){ - *n=*n*10+*s-'0'; - s++; - } - return s; -} -char *rdenv(char *name){ - char *v; - int fd, size; - fd=open(name, OREAD); - if(fd<0) return 0; - size=seek(fd, 0, 2); - v=malloc(size+1); - if(v==0){ - fprint(2, "Can't malloc: %r\n"); - exits("no mem"); - } - seek(fd, 0, 0); - read(fd, v, size); - v[size]=0; - close(fd); - return v; + if(offscreen != screen && !buffer) + line(screen, xlp(Pt(x0, y0)), xlp(Pt(x1, y1)), Endsquare, Endsquare, 0, getcolor(c), ZP); } /* * Startup initialization */ -void m_initialize(char *s){ - static int first=1; +void m_initialize(char*) +{ + static int once; int dx, dy; - USED(s); - if(first){ - if(initdraw(0,0,"plot") < 0) - sysfatal("initdraw: %r"); - einit(Emouse); - clipminx=mapminx=screen->r.min.x+4; - clipminy=mapminy=screen->r.min.y+4; - clipmaxx=mapmaxx=screen->r.max.x-5; - clipmaxy=mapmaxy=screen->r.max.y-5; - dx=clipmaxx-clipminx; - dy=clipmaxy-clipminy; - if(dx>dy){ - mapminx+=(dx-dy)/2; - mapmaxx=mapminx+dy; - } - else{ - mapminy+=(dy-dx)/2; - mapmaxy=mapminy+dx; - } - first=0; - offscreen = screen; + + if(once) + return; + once = 1; + + if(initdraw(nil, nil, "plot") < 0) + sysfatal("initdraw: %r"); +///// einit(Emouse); + offscreen = allocimage(display, insetrect(screen->r, 4), screen->chan, 0, -1); + if(offscreen == nil) + sysfatal("Can't double buffer\n"); + clipminx = mapminx = screen->r.min.x+4; + clipminy = mapminy = screen->r.min.y+4; + clipmaxx = mapmaxx = screen->r.max.x-5; + clipmaxy = mapmaxy = screen->r.max.y-5; + dx = clipmaxx-clipminx; + dy = clipmaxy-clipminy; + if(dx>dy){ + mapminx += (dx-dy)/2; + mapmaxx = mapminx+dy; + } + else{ + mapminy += (dy-dx)/2; + mapmaxy = mapminy+dx; } } /* * Clean up when finished */ -void m_finish(void){ +void m_finish(void) +{ m_swapbuf(); } -void m_swapbuf(void){ - if(offscreen!=screen) - draw(screen, offscreen->r, offscreen, nil, offscreen->r.min); +void m_swapbuf(void) +{ + draw(screen, insetrect(screen->r, 4), offscreen, nil, offscreen->r.min); flushimage(display, 1); } -void m_dblbuf(void){ - if(offscreen==screen){ - offscreen=allocimage(display, insetrect(screen->r, 4), screen->chan, 0, -1); - if(offscreen==0){ - fprintf(stderr, "Can't double buffer\n"); - offscreen=screen; - } - } +void m_dblbuf(void) +{ + buffer = 1; } -/* Assume colormap entry because + +/* * Use cache to avoid repeated allocation. */ struct{ @@ -127,16 +148,14 @@ return icache[j].i; i = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, v); - if(i == nil){ - fprint(2, "plot: can't allocate image for color: %r\n"); - exits("allocimage"); - } + if(i == nil) + sysfatal("plot: can't allocate image for color: %r"); for(j=0; j