CCL Home Page
Up Directory CCL gp.c
/*
   * 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;
}
Modified: Thu Feb 22 17:00:00 1996 GMT
Page accessed 5625 times since Sat Apr 17 22:03:06 1999 GMT