/* * 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 "gp.h" #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 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); 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 < colormapsize; c++) colormap[c] = c; /* hope for the best */ } XSetBackground (display, gc, colormap[0]); XSetForeground (display, gc, colormap[1]); XSetFillStyle (display, gc, FillSolid); { /* window geometry */ int x, y, m; unsigned int width, height; m = XParseGeometry ("512x512+0+0", &x, &y, &width, &height); m = XParseGeometry (getenv ("GP"), &x, &y, &width, &height); if (m & WidthValue && !((m & HeightValue))) height = width; if (m & XNegative) x += DisplayWidth (display, screen) - width - 2; if (m & YNegative) y += DisplayHeight (display, screen) - height - 2; window = XCreateSimpleWindow (display, RootWindow (display, screen), x, y, /* origin */ width, height, /* size */ 1, /* border width */ colormap[1], /* border color */ colormap[0] /* background color */ ); dv.xmin = 0; dv.xmax = width - 1; dv.ymin = height - 1; dv.ymax = 0; dv.xu = width; /* should query server for aspect */ dv.yu = height; } XStoreName (display, window, name); XSelectInput (display, window, EventMask); XMapWindow (display, window); waitevent (ExposureMask); /* wait permission for drawing */ if (DoesBackingStore (ScreenOfDisplay (display, screen))) { /* lazy redraw */ XSetWindowAttributes a; a.backing_store = Always; /* even when iconified */ a.bit_gravity = StaticGravity; /* even when resized */ XChangeWindowAttributes (display, window, CWBackingStore | CWBitGravity, &a); } canvas = window; return &dv; } void dvclose (int wait) { if (wait) waitinput (closecursor); XCloseDisplay (display); } void dvclear (int wait) { if (wait) waitinput (waitcursor); if (canvas == window) XClearWindow (display, window); else { int old = dvcolor (0); dvbox (0, dv.xu, 0, dv.yu); dvcolor (old); } } void dvflush (void) { XFlush (display); } void dvwait (int t) { void usleep (unsigned); /* sleep microseconds */ dvflush (); if (t >= 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, real r, real g, real 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 = xmin; r.y = ymin; r.width = xmax - xmin + 1; r.height = 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 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 = 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 = x - size; s[0].y1 = y; s[0].x2 = x + size; s[0].y2 = y; s[1].x1 = x; s[1].y1 = y - size; s[1].x2 = x; s[1].y2 = y + size; XDrawSegments (display, canvas, gc, s, 2); break; case '*': dx = size * 0.5; dy = size * 0.866; s[0].x1 = x - size; s[0].y1 = y; s[0].x2 = x + size; s[0].y2 = y; s[1].x1 = x + dx; s[1].y1 = y + dy; s[1].x2 = x - dx; s[1].y2 = y - dy; s[2].x1 = x + dx; s[2].y1 = y - dy; s[2].x2 = x - dx; s[2].y2 = y + dy; XDrawSegments (display, canvas, gc, s, 3); break; case 'x': dx = size; dy = size; s[0].x1 = x + dx; s[0].y1 = y + dy; s[0].x2 = x - dx; s[0].y2 = y - dy; s[1].x1 = x + dx; s[1].y1 = y - dy; s[1].x2 = x - dx; s[1].y2 = 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 = x - size; p[0].y = y; p[1].x = x; p[1].y = y + size; p[2].x = x + size; p[2].y = y; p[3].x = x; p[3].y = y - size; p[4].x = x - size; p[4].y = y; XDrawLines (display, canvas, gc, p, 5, CoordModeOrigin); break; case 'D': p[0].x = x - size; p[0].y = y; p[1].x = x; p[1].y = y + size; p[2].x = x + size; p[2].y = y; p[3].x = x; p[3].y = y - size; p[4].x = x - size; p[4].y = 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 = x; point[i].y = 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++ = '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, dv.xu, 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, dv.xu, dv.yu, 0, 0); #if 0 XFlush (display); #endif } void dvfrontbuffer (void) { canvas = (Drawable) window; } void dvbackbuffer (void) { canvas = (Drawable) back; }