/* * Last edited on 2016-09-13 15:39:38 by stolfilocal * dv/X11.c * device primitives for X11 * Luiz Henrique de Figueiredo (lhf@visgraf.impa.br) * 22 Nov 95 */ #include #include #include #include #include #include #include #include #include #define vector(n,t) ( (t*) malloc((n)*sizeof(t)) ) #define revector(p,n) ( (void*) realloc(p,(n)*sizeof(*p)) ) #define colormapsize 256 /* was DisplayCells(display,screen) */ /* add PointerMotionMask for idle motion report */ #define EventMask \ (ButtonPressMask|ButtonReleaseMask|KeyPressMask|ButtonMotionMask|ExposureMask) #define Idle (-1) typedef unsigned long Pixel; static Box dv; static Display* display; static int screen; static Window window; static Drawable canvas; static Pixmap back=0; static GC gc; static Colormap cm; static Cursor waitcursor; static Cursor closecursor; static Cursor busycursor; static XFontStruct* font=NULL; static int color=1; static int marksize=3; static char* marktype="."; static Pixel* colormap; static int polymode=0; static XPoint* point=NULL; static int points=0; static int maxpoints=0; static void waitinput (Cursor cursor); static void waitevent (int mask); Box* dvopen(char* name) { display=XOpenDisplay(NULL); if (display==NULL) { fprintf(stderr,"%s: cannot open X display [%s]\n",name,XDisplayName(NULL)); exit(1); } screen=DefaultScreen(display); gc=DefaultGC(display,screen); cm=DefaultColormap(display,screen); font=XQueryFont(display,XGContextFromGC(gc)); waitcursor=XCreateFontCursor(display,XC_icon); closecursor=XCreateFontCursor(display,XC_pirate); busycursor=XCreateFontCursor(display,XC_watch); colormap=vector(colormapsize,Pixel); colormap[0]=WhitePixel(display,screen); colormap[1]=BlackPixel(display,screen); { /* in case use color before binding */ int c; for (c=2; c=0) usleep(1000*t); /* sleep t miliseconds */ else waitinput(waitcursor); } int dvpalette(int c, char* name) { XColor C; if (c<0 || c>=colormapsize) return 0; if (XParseColor(display,cm,name,&C) && XAllocColor(display,cm,&C)) { colormap[c]=C.pixel; if (c==0) /* color 0 is background */ { XSetWindowBackground(display,window,colormap[c]); XSetBackground(display,gc,colormap[c]); XClearWindow(display,window); } return 1; } else return 0; } #define C(x) round((x)*(0x0ffff)) int dvrgb(int c, double r, double g, double b) { char name[]="#RRRRGGGGBBBB"; sprintf(name,"#%04X%04X%04X",C(r),C(g),C(b)); return dvpalette(c,name); } #undef C int dvcolor(int c) { if (c<0 || c>=colormapsize) return -colormapsize; else { int old=color; color=c; XSetForeground(display,gc,colormap[c]); return old; } } int dvfont(char* name) { XFontStruct* f=XLoadQueryFont(display,name); if (f==NULL) return 0; else { XSetFont(display,gc,f->fid); font=f; return 1; } } void dvmark(int size, char* mark) { if (size>0) marksize=size; if (mark!=NULL && *mark!=0) marktype=mark; } void dvclip(int xmin, int xmax, int ymin, int ymax) { XRectangle r; r.x=(short int)xmin; r.y=(short int)ymin; r.width=(short int)(xmax-xmin+1); r.height=(short int)(ymax-ymin+1); XSetClipRectangles(display,gc,0,0,&r,1,Unsorted); } void dvline(int x1, int y1, int x2, int y2) { XDrawLine(display,canvas,gc,x1,y1,x2,y2); } void dvbbox(int xmin, int xmax, int ymin, int ymax) { XDrawRectangle(display,canvas,gc,xmin,ymin,xmax-xmin,ymax-ymin); } void dvbox(int xmin, int xmax, int ymin, int ymax) { XFillRectangle(display,canvas,gc,xmin,ymin,xmax-xmin+1,ymax-ymin+1); } void dvtri(int x1, int y1, int x2, int y2, int x3, int y3) { dvbegin('f'); dvpoint(x1,y1); dvpoint(x2,y2); dvpoint(x3,y3); dvend(); } #define at(a,b) (m[0]==a && m[1]==b) void dvtext(int x, int y, char* s, char* m) { int n=(int)strlen(s); int w=XTextWidth(font,s,n); int h=font->ascent+font->descent; int opaque=0; y-=font->descent-1; if (m==NULL) m="sw"; if (m[0]=='!') { opaque=1; ++m; } else opaque=0; if (0); else if (at('n', 0 )) { x-=w/2; y+=h; } else if (at('n','e')) { x-=w; y+=h; } else if (at('n','w')) { y+=h; } else if (at('s', 0 )) { x-=w/2; } else if (at('s','e')) { x-=w; } else if (at('s','w')) { } else if (at('e', 0 )) { x-=w; y+=h/2; } else if (at('w', 0 )) { y+=h/2; } else if (at('c', 0 )) { x-=w/2; y+=h/2; } if (opaque) XDrawImageString(display,canvas,gc,x,y,s,n); else XDrawString(display,canvas,gc,x,y,s,n); } void dvcircle(int x, int y, int r) { XDrawArc(display,canvas,gc,x-r,y-r,2*r,2*r,0,360*64); } void dvplot(int x, int y) { int size=marksize; char* m; for (m=marktype; *m!=0; m++) switch (*m) { XSegment s[5]; XPoint p[5]; int dx,dy; default: case '.': XDrawPoint(display,canvas,gc,x,y); break; case 'o': XDrawArc(display,canvas,gc,x-size,y-size,2*size,2*size,0,360*64); break; case 'O': XFillArc(display,canvas,gc,x-size,y-size,2*size,2*size,0,360*64); break; case '+': s[0].x1=(short int)(x-size); s[0].y1=(short int)y; s[0].x2=(short int)(x+size); s[0].y2=(short int)y; s[1].x1=(short int)x; s[1].y1=(short int)(y-size); s[1].x2=(short int)x; s[1].y2=(short int)(y+size); XDrawSegments(display,canvas,gc,s,2); break; case '*': dx=(int)(size*0.5); dy=(int)(size*0.866); s[0].x1=(short int)(x-size); s[0].y1=(short int)y; s[0].x2=(short int)(x+size); s[0].y2=(short int)y; s[1].x1=(short int)(x+dx); s[1].y1=(short int)(y+dy); s[1].x2=(short int)(x-dx); s[1].y2=(short int)(y-dy); s[2].x1=(short int)(x+dx); s[2].y1=(short int)(y-dy); s[2].x2=(short int)(x-dx); s[2].y2=(short int)(y+dy); XDrawSegments(display,canvas,gc,s,3); break; case 'x': dx=(int)size; dy=(int)size; s[0].x1=(short int)(x+dx); s[0].y1=(short int)(y+dy); s[0].x2=(short int)(x-dx); s[0].y2=(short int)(y-dy); s[1].x1=(short int)(x+dx); s[1].y1=(short int)(y-dy); s[1].x2=(short int)(x-dx); s[1].y2=(short int)(y+dy); XDrawSegments(display,canvas,gc,s,2); break; case 'b': XDrawRectangle(display,canvas,gc,x-size,y-size,2*size,2*size); break; case 'B': XFillRectangle(display,canvas,gc,x-size,y-size,2*size+1,2*size+1); break; case 'd': p[0].x=(short int)(x-size); p[0].y=(short int)y; p[1].x=(short int)x; p[1].y=(short int)(y+size); p[2].x=(short int)(x+size); p[2].y=(short int)y; p[3].x=(short int)x; p[3].y=(short int)(y-size); p[4].x=(short int)(x-size); p[4].y=(short int)y; XDrawLines(display,canvas,gc,p,5,CoordModeOrigin); break; case 'D': p[0].x=(short int)(x-size); p[0].y=(short int)y; p[1].x=(short int)x; p[1].y=(short int)(y+size); p[2].x=(short int)(x+size); p[2].y=(short int)y; p[3].x=(short int)x; p[3].y=(short int)(y-size); p[4].x=(short int)(x-size); p[4].y=(short int)y; XFillPolygon(display,canvas,gc,p,5,Convex,CoordModeOrigin); break; } } void dvbegin(int mode) { if (point==NULL) point=vector(maxpoints=16,XPoint); polymode=mode; points=0; } int dvpoint(int x, int y) /* should check XMaxRequestSize */ { int i=points++; if (i>=maxpoints) point=revector(point,maxpoints*=2); point[i].x=(short int)x; point[i].y=(short int)y; return points; } void dvend(void) { switch (polymode) { case 'p': /* closed polygonal line */ dvpoint(point[0].x,point[0].y); case 'l': /* open polygonal line */ XDrawLines(display,canvas,gc,point,points,CoordModeOrigin); break; case 'f': /* filled polygon */ dvpoint(point[0].x,point[0].y); XFillPolygon(display,canvas,gc,point,points,Complex,CoordModeOrigin); break; case 'm': /* polymarker (only dots) */ XDrawPoints(display,canvas,gc,point,points,CoordModeOrigin); break; } polymode=0; points=0; } char* dvevent(int wait, int* x, int* y) { XEvent event; unsigned int state=0; if (wait) XWindowEvent(display,window,EventMask,&event); else if (!XCheckWindowEvent(display,window,EventMask,&event)) #if 0 return NULL; #else /* report idle status */ { Window rw,w ; int rx,ry; XQueryPointer(display,window,&rw,&w,&rx,&ry,x,y,&state); event.type=Idle; /* fake event */ } #endif { static char report[]="m123+SCM"; char* r=report; switch (event.type) { case Expose: *x=100000000+event.xexpose.x*10001+event.xexpose.width; *y=100000000+event.xexpose.y*10001+event.xexpose.height; *(r++)='r'; *(r++)=(event.xexpose.count!=0) ? '+' : '-'; /* signal last expose */ break; case ButtonPress: case ButtonRelease: state=event.xbutton.state; *x=event.xbutton.x; *y=event.xbutton.y; *(r++)='b'; *(r++)=(char)('0'+event.xbutton.button); *(r++)=(event.type==ButtonPress) ? '+' : '-'; break; case KeyPress: case KeyRelease: report[1]=0; XLookupString(&event.xkey,report+1,sizeof(report)-1,NULL,NULL); state=event.xkey.state; *x=event.xkey.x; *y=event.xkey.y; *(r++)='k'; r++; /* lazy */ *(r++)=(event.type==KeyPress) ? '+' : '-'; break; case MotionNotify: #if 1 while (XEventsQueued(display,QueuedAfterReading)>0) { XEvent ahead; XPeekEvent(display,&ahead); if (ahead.type!=MotionNotify) break; if (ahead.xmotion.window!=window) break; XWindowEvent(display,window,EventMask,&event); } #endif state=event.xmotion.state; #if 1 *x=event.xmotion.x; *y=event.xmotion.y; #else { Window rw,w ; int rx,ry; XQueryPointer(display,window,&rw,&w,&rx,&ry,x,y,&state); } #endif case Idle: *(r++)=(event.type==MotionNotify) ? 'm' : 'i'; if (state&Button1Mask) *(r++)='1'; if (state&Button2Mask) *(r++)='2'; if (state&Button3Mask) *(r++)='3'; *(r++)='+'; break; } if (state&ShiftMask) *(r++)='S'; if (state&ControlMask) *(r++)='C'; if (state&Mod1Mask) *(r++)='M'; /* meta is Mod1*/ *(r++)=0; return report; } } static void waitinput(Cursor cursor) { XDefineCursor(display,window,cursor); waitevent(ButtonReleaseMask|KeyPressMask); XUndefineCursor(display,window); } static void waitevent(int mask) { XEvent event; XWindowEvent(display,window,mask,&event); } void dvdoublebuffer(int on) { if (on) { back=XCreatePixmap(display,window,(unsigned int)dv.xu,(unsigned int)dv.yu,8); dvbackbuffer(); dvclear(0); } else if (back!=0) { XFreePixmap(display,back); back=0; } } void dvswapbuffers(void) { XCopyArea(display,back,window,gc,0,0,(unsigned int)dv.xu,(unsigned int)dv.yu,0,0); #if 0 XFlush(display); #endif } void dvfrontbuffer(void) { canvas=(Drawable) window; } void dvbackbuffer(void) { canvas=(Drawable) back; } void dvdump(int n) { char b[80]; dvflush(); sprintf(b,"xwd -nobdrs -id %d | gzip -c >out%04d.xwd.gz",(int)window,n); system(b); }