home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / plplot / plplot_2 / drivers / xwin.c < prev   
Encoding:
C/C++ Source or Header  |  1994-08-25  |  46.0 KB  |  1,766 lines

  1. /* $Id: xwin.c,v 1.49 1994/08/25 03:58:15 mjl Exp $
  2.  * $Log: xwin.c,v $
  3.  * Revision 1.49  1994/08/25  03:58:15  mjl
  4.  * Change to use default visual for now, since otherwise the current
  5.  * procedure results in a BadMatch when calling XCreateWindow on some systems
  6.  * (Suns).  To really get it right, XGetRGBColormaps or something similar
  7.  * must be used to pair the visual with a compatible colormap.
  8.  *
  9.  * Revision 1.48  1994/08/05  09:25:05  mjl
  10.  * Added the static variable "synchronize", to be set when you want
  11.  * synchronous X operation.  Only for debugging, otherwise it's too slow.
  12.  *
  13.  * Revision 1.47  1994/07/27  22:18:01  mjl
  14.  * Fixed bug in window cleanup and termination that was causing a core dump
  15.  * for apps using multiple plframe widgets.
  16.  *
  17.  * Revision 1.46  1994/07/22  22:20:36  mjl
  18.  * Fixed bug in WM hints, introduced during the last bug fix.  It was causing
  19.  * the window to come up without user intervention and in a poor location for
  20.  * tvtwm.  Now it should get BOTH the default and the user specified cases
  21.  * right regardless of window manager (I hope).
  22.  *
  23.  * Revision 1.45  1994/07/19  22:30:32  mjl
  24.  * All device drivers: enabling macro renamed to PLD_<driver>, where <driver>
  25.  * is xwin, ps, etc.  See plDevs.h for more detail.
  26.  *
  27.  * Revision 1.44  1994/07/18  20:28:46  mjl
  28.  * Fixed a cast.
  29.  *
  30.  * Revision 1.43  1994/07/01  22:38:04  mjl
  31.  * All display-dependent data broken off into a separate structure.  The X
  32.  * driver now saves only one of these XwDisplay structs for each physical
  33.  * X display.  These are then shared between all PLplot streams.  This
  34.  * ensures that using multiple streams -> multiple X windows does not cause
  35.  * abnormal termination due to running out of resources since most are now
  36.  * shared (allocated colors, graphics contexts, etc).  The drawback is that
  37.  * colors are no longer independent between windows, if created by a single
  38.  * process (but this can also be an advantage).
  39.  *
  40.  * Revision 1.42  1994/06/17  21:21:11  mjl
  41.  * Fixed background color for mono displays, should now come up white (much
  42.  * easier to see).  Middle mouse button press now returns world coordinates
  43.  * at cursor, but only correct for last plot on the page (submitted by
  44.  * Mark Glover glover@zombi.res.utc.com).
  45.  *
  46.  * Revision 1.41  1994/06/09  20:05:58  mjl
  47.  * Fixed Visual handling to support grayscale and mono displays.  Enabled
  48.  * exporting of colormap hack flag for other files (plframe.c) that need it.
  49.  *
  50.  * Revision 1.40  1994/05/27  22:19:17  mjl
  51.  * Window now placed properly when offsets (+x+y) are specified.  Thanks
  52.  * to Mark S. Glover (glover@zombi.res.utc.com) for the fix.
  53. */
  54.  
  55. /*    xwin.c
  56.  
  57.     PLPLOT X-windows device driver.
  58. */
  59. #include "plDevs.h"
  60.  
  61. #ifdef PLD_xwin
  62.  
  63. #include "plplotP.h"
  64. #include "plplotX.h"
  65. #include "drivers.h"
  66. #include "plevent.h"
  67.  
  68. static int synchronize = 0;    /* change to 1 for synchronized operation */
  69.                 /* for debugging only */
  70.  
  71. /* When DEFAULT_VISUAL is 1, DefaultVisual() is used to get the visual.
  72.  * Otherwise, the visual is obtained using XGetVisualInfo() to make a
  73.  * match.
  74.  */
  75.  
  76. #define DEFAULT_VISUAL 1
  77.  
  78. /* Set constants for dealing with colormap.  In brief:
  79.  *
  80.  * ccmap        When set, turns on custom color map
  81.  *
  82.  * XWM_COLORS        Number of low "pixel" values to copy.  
  83.  * CMAP0_COLORS        Color map 0 entries.  
  84.  * CMAP1_COLORS        Color map 1 entries.  
  85.  * MAX_COLORS        Maximum colors period.
  86.  *
  87.  * See Init_CustomCmap() and  Init_DefaultCmap() for more info.
  88.  * Set ccmap at your own risk -- still under development.
  89.  */
  90.  
  91. int plplot_ccmap = 0;
  92.  
  93. #define XWM_COLORS 70
  94. #define CMAP0_COLORS 16
  95. #define CMAP1_COLORS 100
  96. #define MAX_COLORS 256
  97.  
  98. /* Variables to hold RGB components of given colormap. */
  99. /* Used in an ugly hack to get past some X11R5 and TK limitations. */
  100.  
  101. static int  sxwm_colors_set;
  102. static XColor sxwm_colors[256];
  103.  
  104. /* Keep pointers to all the displays in use */
  105.  
  106. static XwDisplay *xwDisplay[PLXDISPLAYS];
  107.  
  108. /* Function prototypes */
  109.  
  110. static void  Init        (PLStream *pls);
  111. static void  Init_main        (PLStream *pls);
  112. static void  Init_Colors    (PLStream *pls);
  113. static void  Init_CustomCmap    (PLStream *pls);
  114. static void  Init_DefaultCmap    (PLStream *pls);
  115. static void  Map_main        (PLStream *pls);
  116. static void  WaitForPage    (PLStream *pls);
  117. static void  HandleEvents    (PLStream *pls);
  118. static void  ColorInit        (PLStream *pls);
  119. static void  Cmap0Init        (PLStream *pls);
  120. static void  Cmap1Init        (PLStream *pls);
  121. static void  CreatePixmap    (PLStream *pls);
  122. static void  fill_polygon    (PLStream *pls);
  123. static void  Colorcpy        (XColor *, XColor *);
  124.  
  125. static void  MasterEH        (PLStream *, XEvent *);
  126. static void  KeyEH        (PLStream *, XEvent *);
  127. static void  MouseEH        (PLStream *, XEvent *);
  128. static void  ExposeEH        (PLStream *, XEvent *);
  129. static void  ResizeEH        (PLStream *, XEvent *);
  130.  
  131. static void  ExposeCmd        (PLStream *);
  132. static void  ResizeCmd        (PLStream *, PLWindow *);
  133. static void  RedrawCmd        (PLStream *);
  134.  
  135. /*----------------------------------------------------------------------*\
  136.  * plD_init_xw()
  137.  *
  138.  * Initialize device.
  139.  * X-dependent stuff done in Init().
  140. \*----------------------------------------------------------------------*/
  141.  
  142. void
  143. plD_init_xw(PLStream *pls)
  144. {
  145.     XwDev *dev;
  146.     int xmin = 0;
  147.     int xmax = PIXELS_X - 1;
  148.     int ymin = 0;
  149.     int ymax = PIXELS_Y - 1;
  150.  
  151.     float pxlx = (double) PIXELS_X / (double) LPAGE_X;
  152.     float pxly = (double) PIXELS_Y / (double) LPAGE_Y;
  153.  
  154.     dbug_enter("plD_init_xw");
  155.  
  156.     pls->termin = 1;        /* is an interactive terminal */
  157.     pls->icol0 = 1;
  158.     pls->width = 1;
  159.     pls->bytecnt = 0;
  160.     pls->page = 0;
  161.     pls->plbuf_write = 1;
  162.     pls->dev_flush = 1;        /* Want to handle our own flushes */
  163.     pls->dev_fill0 = 1;        /* Can do solid fills */
  164.  
  165. /* Allocate and initialize device-specific data */
  166.  
  167.     if (pls->dev != NULL)
  168.     free((void *) pls->dev);
  169.  
  170.     pls->dev = calloc(1, (size_t) sizeof(XwDev));
  171.     if (pls->dev == NULL)
  172.     plexit("plD_init_xw: Out of memory.");
  173.  
  174.     dev = (XwDev *) pls->dev;
  175.  
  176. /* Set up flags that determine what we are writing to */
  177. /* If nopixmap is set, ignore db */
  178.  
  179.     if (pls->nopixmap) {
  180.     dev->write_to_pixmap = 0;
  181.     pls->db = 0;
  182.     }
  183.     else
  184.     dev->write_to_pixmap = 1;
  185.  
  186.     dev->write_to_window = ! pls->db;
  187.  
  188. /* X-specific initialization */
  189.  
  190.     Init(pls);
  191.  
  192. /* Get ready for plotting */
  193.  
  194.     dev->xlen = xmax - xmin;
  195.     dev->ylen = ymax - ymin;
  196.  
  197.     dev->xscale_init = (double) (dev->init_width-1) / (double) dev->xlen;
  198.     dev->yscale_init = (double) (dev->init_height-1) / (double) dev->ylen;
  199.  
  200.     dev->xscale = dev->xscale_init;
  201.     dev->yscale = dev->yscale_init;
  202.  
  203.     plP_setpxl(pxlx, pxly);
  204.     plP_setphy(xmin, xmax, ymin, ymax);
  205. }
  206.  
  207. /*----------------------------------------------------------------------*\
  208.  * plD_line_xw()
  209.  *
  210.  * Draw a line in the current color from (x1,y1) to (x2,y2).
  211. \*----------------------------------------------------------------------*/
  212.  
  213. void
  214. plD_line_xw(PLStream *pls, short x1a, short y1a, short x2a, short y2a)
  215. {
  216.     XwDev *dev = (XwDev *) pls->dev;
  217.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  218.  
  219.     int x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
  220.     static long count = 0, max_count = 20;
  221.  
  222.     if (dev->is_main) {
  223.     if ( (++count/max_count)*max_count == count) {
  224.         count = 0;
  225.         HandleEvents(pls);    /* Check for events */
  226.     }
  227.     }
  228.  
  229.     y1 = dev->ylen - y1;
  230.     y2 = dev->ylen - y2;
  231.  
  232.     x1 = x1 * dev->xscale;
  233.     x2 = x2 * dev->xscale;
  234.     y1 = y1 * dev->yscale;
  235.     y2 = y2 * dev->yscale;
  236.  
  237.     if (dev->write_to_window)
  238.     XDrawLine(xwd->display, dev->window, xwd->gc, x1, y1, x2, y2);
  239.  
  240.     if (dev->write_to_pixmap)
  241.     XDrawLine(xwd->display, dev->pixmap, xwd->gc, x1, y1, x2, y2);
  242. }
  243.  
  244. /*----------------------------------------------------------------------*\
  245.  * plD_polyline_xw()
  246.  *
  247.  * Draw a polyline in the current color from (x1,y1) to (x2,y2).
  248. \*----------------------------------------------------------------------*/
  249.  
  250. void
  251. plD_polyline_xw(PLStream *pls, short *xa, short *ya, PLINT npts)
  252. {
  253.     XwDev *dev = (XwDev *) pls->dev;
  254.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  255.  
  256.     PLINT i;
  257.     XPoint pts[PL_MAXPOLY];
  258.     static long count = 0, max_count = 10;
  259.  
  260.     if (dev->is_main) {
  261.     if ( (++count/max_count)*max_count == count) {
  262.         count = 0;
  263.         HandleEvents(pls);    /* Check for events */
  264.     }
  265.     }
  266.  
  267.     if (npts > PL_MAXPOLY)
  268.     plexit("Error -- too many points in polyline\n");
  269.  
  270.     for (i = 0; i < npts; i++) {
  271.     pts[i].x = dev->xscale * xa[i];
  272.     pts[i].y = dev->yscale * (dev->ylen - ya[i]);
  273.     }
  274.  
  275.     if (dev->write_to_window)
  276.     XDrawLines(xwd->display, dev->window, xwd->gc, pts, npts,
  277.            CoordModeOrigin);
  278.  
  279.     if (dev->write_to_pixmap)
  280.     XDrawLines(xwd->display, dev->pixmap, xwd->gc, pts, npts,
  281.            CoordModeOrigin);
  282. }
  283.  
  284. /*----------------------------------------------------------------------*\
  285.  * plD_eop_xw()
  286.  *
  287.  * End of page.  User must click left mouse button to continue.
  288. \*----------------------------------------------------------------------*/
  289.  
  290. void
  291. plD_eop_xw(PLStream *pls)
  292. {
  293.     XwDev *dev = (XwDev *) pls->dev;
  294.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  295.  
  296.     dbug_enter("plD_eop_xw");
  297.  
  298.     XFlush(xwd->display);
  299.     if (pls->db)
  300.     ExposeCmd(pls);
  301.     
  302.     if ( ! pls->nopause)
  303.     WaitForPage(pls);
  304. }
  305.  
  306. /*----------------------------------------------------------------------*\
  307.  * plD_bop_xw()
  308.  *
  309.  * Set up for the next page.
  310. \*----------------------------------------------------------------------*/
  311.  
  312. void
  313. plD_bop_xw(PLStream *pls)
  314. {
  315.     XwDev *dev = (XwDev *) pls->dev;
  316.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  317.  
  318.     dbug_enter("plD_bop_xw");
  319.  
  320.     if (dev->write_to_window) {
  321.     XClearWindow(xwd->display, dev->window);
  322.     }
  323.     if (dev->write_to_pixmap) {
  324.     XSetForeground(xwd->display, xwd->gc, xwd->cmap0[0].pixel);
  325.     XFillRectangle(xwd->display, dev->pixmap, xwd->gc, 0, 0,
  326.                dev->width, dev->height);
  327.     XSetForeground(xwd->display, xwd->gc, xwd->curcolor.pixel);
  328.     }
  329.     XSync(xwd->display, 0);
  330.     pls->page++;
  331. }
  332.  
  333. /*----------------------------------------------------------------------*\
  334.  * plD_tidy_xw()
  335.  *
  336.  * Close graphics file
  337. \*----------------------------------------------------------------------*/
  338.  
  339. void
  340. plD_tidy_xw(PLStream *pls)
  341. {
  342.     XwDev *dev = (XwDev *) pls->dev;
  343.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  344.  
  345.     dbug_enter("plD_tidy_xw");
  346.  
  347.     if (dev->is_main) {
  348.     XDestroyWindow(xwd->display, dev->window);
  349.     if (dev->write_to_pixmap) 
  350.         XFreePixmap(xwd->display, dev->pixmap);
  351.     }
  352.  
  353.     xwd->count--;
  354.     if (xwd->count == 0) {
  355.     XFreeGC(xwd->display, xwd->gc);
  356.     XCloseDisplay(xwd->display);
  357.     free_mem(xwDisplay[xwd->ixwd]);
  358.     }
  359.     pls->plbuf_write = 0;
  360. }
  361.  
  362. /*----------------------------------------------------------------------*\
  363.  * plD_state_xw()
  364.  *
  365.  * Handle change in PLStream state (color, pen width, fill attribute, etc).
  366. \*----------------------------------------------------------------------*/
  367.  
  368. void 
  369. plD_state_xw(PLStream *pls, PLINT op)
  370. {
  371.     XwDev *dev = (XwDev *) pls->dev;
  372.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  373.  
  374.     dbug_enter("plD_state_xw");
  375.  
  376.     if (dev->is_main) {
  377.     HandleEvents(pls);    /* Check for events */
  378.     }
  379.  
  380.     switch (op) {
  381.  
  382.     case PLSTATE_WIDTH:
  383.     break;
  384.  
  385.     case PLSTATE_COLOR0:{
  386.     int icol0 = pls->icol0;
  387.     if ( ! xwd->color) {
  388.         xwd->curcolor.pixel = xwd->fgcolor.pixel;
  389.         XSetForeground(xwd->display, xwd->gc, xwd->curcolor.pixel);
  390.     }
  391.     else {
  392.         if (icol0 == PL_RGB_COLOR) {
  393.         PLColor_to_XColor(&pls->curcolor, &xwd->curcolor);
  394.  
  395.         if ( ! XAllocColor(xwd->display, xwd->map, &xwd->curcolor)) {
  396.             fprintf(stderr, "Warning: could not allocate color\n");
  397.             xwd->curcolor.pixel = xwd->fgcolor.pixel;
  398.         }
  399.  
  400.         XSetForeground(xwd->display, xwd->gc, xwd->curcolor.pixel);
  401.         }
  402.         else
  403.         XSetForeground(xwd->display, xwd->gc, xwd->cmap0[icol0].pixel);
  404.     }
  405.     break;
  406.     }
  407.  
  408.     case PLSTATE_COLOR1:{
  409.     int icol1 = (pls->icol1 * (xwd->ncol1-1)) / (pls->ncol1-1);
  410.     if ( ! xwd->color) {
  411.         xwd->curcolor.pixel = xwd->fgcolor.pixel;
  412.         XSetForeground(xwd->display, xwd->gc, xwd->curcolor.pixel);
  413.     }
  414.     else {
  415.         XSetForeground(xwd->display, xwd->gc, xwd->cmap1[icol1].pixel);
  416.     }
  417.     break;
  418.     }
  419.  
  420.     case PLSTATE_CMAP0:
  421.     Cmap0Init(pls);
  422.     break;
  423.  
  424.     case PLSTATE_CMAP1:
  425.     Cmap1Init(pls);
  426.     break;
  427.     }
  428. }
  429.  
  430. /*----------------------------------------------------------------------*\
  431.  * plD_esc_xw()
  432.  *
  433.  * Escape function.
  434.  *
  435.  * Functions:
  436.  *
  437.  *    PLESC_EXPOSE    Force an expose
  438.  *    PLESC_RESIZE    Force a resize
  439.  *    PLESC_REDRAW    Force a redraw
  440.  *    PLESC_FLUSH    Flush X event buffer
  441.  *    PLESC_FILL    Fill polygon
  442.  *    PLESC_EH    Handle events only
  443.  *
  444. \*----------------------------------------------------------------------*/
  445.  
  446. void
  447. plD_esc_xw(PLStream *pls, PLINT op, void *ptr)
  448. {
  449.     XwDev *dev = (XwDev *) pls->dev;
  450.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  451.  
  452.     dbug_enter("plD_esc_xw");
  453.  
  454.     switch (op) {
  455.     case PLESC_EXPOSE:
  456.     ExposeCmd(pls);
  457.     break;
  458.  
  459.     case PLESC_RESIZE:
  460.     ResizeCmd(pls, (PLWindow *) ptr);
  461.     break;
  462.  
  463.     case PLESC_REDRAW:
  464.     RedrawCmd(pls);
  465.     break;
  466.  
  467.     case PLESC_FLUSH:
  468.     HandleEvents(pls);
  469.     XFlush(xwd->display);
  470.     break;
  471.  
  472.     case PLESC_FILL:
  473.     fill_polygon(pls);
  474.     break;
  475.  
  476.     case PLESC_EH:
  477.     HandleEvents(pls);
  478.     break;
  479.     }
  480. }
  481.  
  482. /*----------------------------------------------------------------------*\
  483.  * fill_polygon()
  484.  *
  485.  * Fill polygon described in points pls->dev_x[] and pls->dev_y[].
  486.  * Only solid color fill supported.
  487. \*----------------------------------------------------------------------*/
  488.  
  489. static void
  490. fill_polygon(PLStream *pls)
  491. {
  492.     XwDev *dev = (XwDev *) pls->dev;
  493.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  494.     XPoint pts[PL_MAXPOLY];
  495.  
  496.     static long count = 0, max_count = 10;
  497.     int i, outline_only=0;
  498.  
  499.     if (dev->is_main) {
  500.     if ( (++count/max_count)*max_count == count) {
  501.         count = 0;
  502.         HandleEvents(pls);    /* Check for events */
  503.     }
  504.     }
  505.  
  506.     if (pls->dev_npts > PL_MAXPOLY)
  507.     plexit("Error -- too many points in polygon\n");
  508.  
  509.     for (i = 0; i < pls->dev_npts; i++) {
  510.     pts[i].x = dev->xscale * pls->dev_x[i];
  511.     pts[i].y = dev->yscale * (dev->ylen - pls->dev_y[i]);
  512.     }
  513.  
  514. /*
  515.  * For an interesting effect during fills, turn on outline_only.
  516.  * Mostly for debugging.
  517.  */
  518.  
  519.     if (outline_only) {
  520.     if (dev->write_to_window)
  521.         XDrawLines(xwd->display, dev->window, xwd->gc, pts, pls->dev_npts,
  522.                CoordModeOrigin);
  523.  
  524.     if (dev->write_to_pixmap)
  525.         XDrawLines(xwd->display, dev->pixmap, xwd->gc, pts, pls->dev_npts,
  526.                CoordModeOrigin);
  527.     }
  528.     else {
  529.     if (dev->write_to_window)
  530.         XFillPolygon(xwd->display, dev->window, xwd->gc,
  531.              pts, pls->dev_npts, Nonconvex, CoordModeOrigin);
  532.  
  533.     if (dev->write_to_pixmap)
  534.         XFillPolygon(xwd->display, dev->pixmap, xwd->gc,
  535.              pts, pls->dev_npts, Nonconvex, CoordModeOrigin);
  536.     }
  537. }
  538.  
  539. /*----------------------------------------------------------------------*\
  540.  * Init()
  541.  *
  542.  * Xlib initialization routine.
  543.  *
  544.  * Controlling routine for X window creation and/or initialization.
  545.  * The user may customize the window in the following ways:
  546.  *
  547.  * display:    pls->OutFile (use plsfnam() or -display option) 
  548.  * size:    pls->xlength, pls->ylength (use plspage() or -geo option)
  549.  * bg color:    pls->cmap0[0] (use plscolbg() or -bg option)
  550. \*----------------------------------------------------------------------*/
  551.  
  552. static void
  553. Init(PLStream *pls)
  554. {
  555.     XwDev *dev = (XwDev *) pls->dev;
  556.     XwDisplay *xwd;
  557.  
  558.     Window root;
  559.     int i, x, y;
  560.  
  561.     dbug_enter("Init");
  562.  
  563. /* See if display matches any already in use, and if so use that */
  564.  
  565.     dev->xwd = NULL;
  566.     for (i = 0; i < PLXDISPLAYS; i++) {
  567.     if (xwDisplay[i] == NULL)
  568.         continue;
  569.  
  570.     if (strcmp(xwDisplay[i]->displayName, pls->FileName) == 0) {
  571.         dev->xwd = xwDisplay[i];
  572.         break;
  573.     }
  574.     }
  575.  
  576. /* If no display matched, create a new one */
  577.  
  578.     if (dev->xwd == NULL) {
  579.     dev->xwd = (XwDisplay *) calloc(1, (size_t) sizeof(XwDisplay));
  580.     if (dev->xwd == NULL)
  581.         plexit("Init: Out of memory.");
  582.  
  583.     for (i = 0; i < PLXDISPLAYS; i++) {
  584.         if (xwDisplay[i] == NULL)
  585.         break;
  586.     }
  587.     if (i == PLXDISPLAYS) 
  588.         plexit("Init: Out of xwDisplay's.");
  589.  
  590.     xwDisplay[i] = xwd = (XwDisplay *) dev->xwd;
  591.     xwd->count = 1;
  592.     }
  593.     else {
  594.     xwd = (XwDisplay *) dev->xwd;
  595.     xwd->count++;
  596.     }
  597.     xwd->ixwd = i;
  598.     
  599. /* Open display, initialize color map and color values */
  600.  
  601.     if (xwd->count == 1) {
  602.     xwd->display = XOpenDisplay(pls->FileName);
  603.     if (xwd->display == NULL) {
  604.         fprintf(stderr, "Can't open display\n");
  605.         exit(1);
  606.     }
  607.     xwd->displayName = pls->FileName;
  608.     xwd->screen = DefaultScreen(xwd->display);
  609.     if (synchronize) 
  610.         XSynchronize(xwd->display, 1);
  611.  
  612.     Init_Colors(pls);
  613.     }
  614.  
  615. /* If not plotting into a child window, need to create main window now */
  616.  
  617.     if (pls->window_id == 0) {
  618.     dev->is_main = TRUE;
  619.     Init_main(pls);
  620.     }
  621.     else {
  622.     dev->is_main = FALSE;
  623.     dev->window = pls->window_id;
  624.     }
  625.     XSetWindowColormap( xwd->display, dev->window, xwd->map );
  626.  
  627. /* GC creation and initialization */
  628.  
  629.     if (xwd->count == 1) {
  630.     xwd->gc = XCreateGC(xwd->display, dev->window, 0, 0);
  631.     }
  632.  
  633. /* Get initial drawing area dimensions */
  634.  
  635.     (void) XGetGeometry(xwd->display, dev->window, &root, &x, &y,
  636.             &dev->width, &dev->height, &dev->border, &xwd->depth);
  637.  
  638.     dev->init_width = dev->width;
  639.     dev->init_height = dev->height;
  640.  
  641. /* Create pixmap for holding plot image (for expose events). */
  642.  
  643.     if (dev->write_to_pixmap) 
  644.     CreatePixmap(pls);
  645.  
  646. /* Set drawing color */
  647.  
  648.     plD_state_xw(pls, PLSTATE_COLOR0);
  649.  
  650.     XSetWindowBackground(xwd->display, dev->window, xwd->cmap0[0].pixel);
  651.     XSetBackground(xwd->display, xwd->gc, xwd->cmap0[0].pixel);
  652.  
  653. /* If main window, need to map it and wait for exposure */
  654.  
  655.     if (dev->is_main) 
  656.     Map_main(pls);
  657. }
  658.  
  659. /*----------------------------------------------------------------------*\
  660.  * Init_main()
  661.  *
  662.  * Create main window using standard Xlib calls.
  663. \*----------------------------------------------------------------------*/
  664.  
  665. static void
  666. Init_main(PLStream *pls)
  667. {
  668.     XwDev *dev = (XwDev *) pls->dev;
  669.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  670.  
  671.     Window root;
  672.     XSizeHints hint;
  673.     int x, y;
  674.     U_INT width, height, border, depth;
  675.     char header[80];
  676.     Cursor cross_cursor;
  677.  
  678.     dbug_enter("Init_main");
  679.  
  680. /* Get root window geometry */
  681.  
  682.     (void) XGetGeometry(xwd->display, DefaultRootWindow(xwd->display),
  683.             &root, &x, &y, &width, &height, &border, &depth);
  684.  
  685.     dev->border = 5;
  686.     hint.flags = 0;
  687.  
  688. /* Set window size */
  689. /* Need to be careful to set XSizeHints flags correctly */
  690.  
  691.     if (pls->xlength == 0 && pls->ylength == 0)
  692.     hint.flags |= PSize;
  693.     else
  694.     hint.flags |= USSize;
  695.  
  696.     if (pls->xlength == 0)
  697.     pls->xlength = width * 0.75;
  698.     if (pls->ylength == 0)
  699.     pls->ylength = height * 0.75;
  700.  
  701.     if (pls->xlength > width)
  702.     pls->xlength = width - dev->border * 2;
  703.     if (pls->ylength > height)
  704.     pls->ylength = height - dev->border * 2;
  705.  
  706.     hint.width = (int) pls->xlength;
  707.     hint.height = (int) pls->ylength;
  708.  
  709. /* Set window position if specified by the user. */
  710. /* Otherwise leave up to the window manager */
  711.  
  712.     if (pls->xoffset != 0 || pls->yoffset != 0) {
  713.     hint.flags |= USPosition;
  714.     hint.x = (int) pls->xoffset;
  715.     hint.y = (int) pls->yoffset;
  716.     }
  717.  
  718. /* Window title */
  719.  
  720.     sprintf(header, "plplot");
  721.  
  722. /* Window creation */
  723.  
  724.     dev->window =
  725.     XCreateWindow( xwd->display,
  726.                DefaultRootWindow(xwd->display),
  727.                hint.x, hint.y, hint.width, hint.height,
  728.                dev->border, xwd->depth,
  729.                InputOutput, xwd->visual,
  730.                0, NULL );
  731.  
  732.     XSetStandardProperties(xwd->display, dev->window, header, header,
  733.                None, 0, 0, &hint);
  734.  
  735. /* Set cursor to crosshair */
  736.  
  737.     cross_cursor = XCreateFontCursor(xwd->display, XC_crosshair);
  738.     XDefineCursor(xwd->display, dev->window, cross_cursor);
  739. }
  740.  
  741. /*----------------------------------------------------------------------*\
  742.  * Map_main()
  743.  *
  744.  * Sets up event handlers, maps main window and waits for exposure.
  745. \*----------------------------------------------------------------------*/
  746.  
  747. static void
  748. Map_main(PLStream *pls)
  749. {
  750.     XwDev *dev = (XwDev *) pls->dev;
  751.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  752.  
  753.     XEvent the_event;
  754.  
  755.     dbug_enter("Map_main");
  756.  
  757. /* Input event selection */
  758.  
  759.     XSelectInput(xwd->display, dev->window,
  760.          ButtonPressMask | KeyPressMask |
  761.          ExposureMask | StructureNotifyMask);
  762.  
  763. /* Window mapping */
  764.  
  765.     XMapRaised(xwd->display, dev->window);
  766.  
  767. /* Wait for exposure */
  768. /* Remove extraneous expose events from the event queue */
  769.  
  770.     for (;;) {
  771.     XNextEvent(xwd->display, &the_event);
  772.     if (the_event.type == Expose) {
  773.         while (XCheckMaskEvent(xwd->display, ExposureMask, &the_event));
  774.         break;
  775.     }
  776.     }
  777. }
  778.  
  779. /*----------------------------------------------------------------------*\
  780.  * WaitForPage()
  781.  *
  782.  * This routine waits for the user to advance the plot, while handling
  783.  * all other events.
  784. \*----------------------------------------------------------------------*/
  785.  
  786. static void
  787. WaitForPage(PLStream *pls)
  788. {
  789.     XwDev *dev = (XwDev *) pls->dev;
  790.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  791.  
  792.     XEvent event;
  793.  
  794.     dbug_enter("WaitForPage");
  795.  
  796.     if ( ! dev->is_main) {
  797.     HandleEvents(pls);    /* Check for events */
  798.     return;
  799.     }
  800.  
  801.     while ( ! dev->exit_eventloop) {
  802.     XNextEvent(xwd->display, &event);
  803.     MasterEH(pls, &event);
  804.     }
  805.     dev->exit_eventloop = FALSE;
  806. }
  807.  
  808. /*----------------------------------------------------------------------*\
  809.  * HandleEvents()
  810.  *
  811.  * Just a front-end to MasterEH(), for use when not actually waiting for
  812.  * an event but only checking the event queue.  
  813. \*----------------------------------------------------------------------*/
  814.  
  815. static void
  816. HandleEvents(PLStream *pls)
  817. {
  818.     XwDev *dev = (XwDev *) pls->dev;
  819.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  820.  
  821.     XEvent event;
  822.  
  823.     if (XCheckMaskEvent(xwd->display, ButtonPressMask | KeyPressMask |
  824.             ExposureMask | StructureNotifyMask, &event))
  825.     MasterEH(pls, &event);
  826. }
  827.  
  828. /*----------------------------------------------------------------------*\
  829.  * MasterEH()
  830.  *
  831.  * Master X event handler routine.
  832.  * Redirects control to routines to handle:
  833.  *    - keyboard events
  834.  *    - mouse events
  835.  *    - expose events
  836.  *    - resize events
  837.  *
  838.  * By supplying a master event handler, the user can take over all event
  839.  * processing.  If events other than those trapped by plplot need handling,
  840.  * just call XSelectInput with the appropriate flags.  The default PLPlot
  841.  * event handling can be modified arbitrarily by changing the event struct.
  842. \*----------------------------------------------------------------------*/
  843.  
  844. static void
  845. MasterEH(PLStream *pls, XEvent *event)
  846. {
  847.     XwDev *dev = (XwDev *) pls->dev;
  848.  
  849.     if (dev->MasterEH != NULL)
  850.     (*dev->MasterEH) (pls, event);
  851.  
  852.     switch (event->type) {
  853.       case KeyPress:
  854.     KeyEH(pls, event);
  855.     break;
  856.  
  857.       case ButtonPress:
  858.     MouseEH(pls, event);
  859.     break;
  860.  
  861.       case Expose:
  862.     ExposeEH(pls, event);
  863.     break;
  864.  
  865.       case ConfigureNotify:
  866.     ResizeEH(pls, event);
  867.     break;
  868.     }
  869. }
  870.  
  871. /*----------------------------------------------------------------------*\
  872.  * KeyEH()
  873.  *
  874.  * Event handler routine for keyboard events.
  875. \*----------------------------------------------------------------------*/
  876.  
  877. static void
  878. KeyEH(PLStream *pls, XEvent *event)
  879. {
  880.     XwDev *dev = (XwDev *) pls->dev;
  881.  
  882.     KeySym keysym;
  883.     PLKey key;
  884.     int count;
  885.     XComposeStatus cs;
  886.  
  887.     dbug_enter("KeyEH");
  888.  
  889. /* Translate event into string */
  890.  
  891.     count = XLookupString((XKeyEvent *) event, key.string, PL_NKEYSTRING,
  892.               &keysym, &cs);
  893.     key.string[count] = '\0';
  894.     key.code = (U_LONG) keysym;
  895.  
  896. #ifdef DEBUG
  897.     printf("Keysym %x, translation: %s\n", keysym, key.string);
  898. #endif
  899.  
  900. /* Call user keypress event handler */
  901. /* Since this is called first, the user can disable all plplot internal
  902.    event handling by setting key.code to 0 and key.string to '\0' */
  903.  
  904.     if (pls->KeyEH != NULL)
  905.     (*pls->KeyEH) (&key, pls->KeyEH_data, &dev->exit_eventloop);
  906.  
  907. /* Handle internal events */
  908.  
  909. /* Advance to next page (i.e. terminate event loop) on a <eol> */
  910. /* Check for both <CR> and <LF> for portability, also a <Page Down> */
  911.  
  912.     if (key.code == PLK_Return ||
  913.     key.code == PLK_Linefeed ||
  914.     key.code == PLK_Next)
  915.     dev->exit_eventloop = TRUE;
  916.  
  917. /* Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake) */
  918.  
  919.     if (key.string[0] == 'Q') {
  920.     pls->nopause = TRUE;
  921.     plexit("");
  922.     }
  923. }
  924.  
  925. /*----------------------------------------------------------------------*\
  926.  * MouseEH()
  927.  *
  928.  * Event handler routine for mouse events.
  929.  * On:
  930.  *   Button1: nothing for now
  931.  *   Button2: spit out device space coordinates
  932.  *   Button3: set page advance flag for later processing
  933. \*----------------------------------------------------------------------*/
  934.  
  935. static void
  936. MouseEH(PLStream *pls, XEvent *event)
  937. {
  938.     XwDev *dev = (XwDev *) pls->dev;
  939.  
  940.     PLMouse mouse;
  941.     float xcoord, ycoord;
  942.  
  943.     dbug_enter("MouseEH");
  944.  
  945.     mouse.button = event->xbutton.button;
  946.     mouse.state = event->xbutton.state;
  947.     mouse.x = (PLFLT)event->xbutton.x / pls->xlength;
  948.     mouse.y = 1.0 - (PLFLT)event->xbutton.y / pls->ylength;
  949.       
  950. /* Call user event handler */
  951. /* Since this is called first, the user can disable all plplot internal
  952.    event handling by setting mouse.button to 0 */
  953.  
  954.     if (pls->MouseEH != NULL)
  955.     (*pls->MouseEH) (&mouse, pls->MouseEH_data, &dev->exit_eventloop);
  956.  
  957.     switch (mouse.button) {
  958.     case Button1:
  959.     break;
  960.  
  961.     case Button2:
  962.     printf("%f\t%f\n", mouse.x, mouse.y);
  963.         xcoord=((event->xbutton.x+1-(pls->vpdxmi)*(pls->xlength))/
  964.                 ((pls->vpdxma-pls->vpdxmi)*pls->xlength))*pls->vpwxma;
  965.         ycoord=((pls->ylength-event->xbutton.y+1-(pls->vpdymi)*(pls->ylength))/
  966.                 ((pls->vpdyma-pls->vpdymi)*pls->ylength))*pls->vpwyma;
  967.     printf("%f\t%f\n", xcoord, ycoord);
  968. #ifdef DEBUG
  969.         printf("[xwin.c:MouseEH:] world X coord = %f\n",
  970.                xcoord);
  971.         printf("[xwin.c:MouseEH:] world Y coord = %f\n",
  972.                ycoord);
  973. #endif /* DEBUG */
  974.     break;
  975.  
  976.     case Button3:
  977.     dev->exit_eventloop = TRUE;
  978.     break;
  979.     }
  980. }
  981.  
  982. /*----------------------------------------------------------------------*\
  983.  * ExposeEH()
  984.  *
  985.  * Event handler routine for expose events.
  986.  * Front end to ExposeCmd() to deal with wierdnesses of Xlib.
  987. \*----------------------------------------------------------------------*/
  988.  
  989. static void
  990. ExposeEH(PLStream *pls, XEvent *event)
  991. {
  992.     XwDev *dev = (XwDev *) pls->dev;
  993.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  994.  
  995.     dbug_enter("ExposeEH");
  996.  
  997. /* Handle expose */
  998.  
  999.     ExposeCmd(pls);
  1000.  
  1001. /* Remove extraneous expose events from the event queue */
  1002.  
  1003.     while (XCheckMaskEvent(xwd->display, ExposureMask, event))
  1004.     ;
  1005. }
  1006.  
  1007. /*----------------------------------------------------------------------*\
  1008.  * ResizeEH()
  1009.  *
  1010.  * Event handler routine for resize events.
  1011.  * Front end to ResizeCmd() to deal with wierdnesses of Xlib.
  1012. \*----------------------------------------------------------------------*/
  1013.  
  1014. static void
  1015. ResizeEH(PLStream *pls, XEvent *event)
  1016. {
  1017.     XwDev *dev = (XwDev *) pls->dev;
  1018.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1019.  
  1020.     PLWindow newwin;
  1021.  
  1022.     dbug_enter("ResizeEH");
  1023.  
  1024.     newwin.width = event->xconfigure.width;
  1025.     newwin.height = event->xconfigure.height;
  1026.  
  1027. /* Only need to resize if size is actually changed */
  1028.  
  1029.     if (newwin.width == dev->width && newwin.height == dev->height)
  1030.     return;
  1031.  
  1032.     ResizeCmd(pls, &newwin);
  1033.  
  1034. /* Remove extraneous expose events from the event queue */
  1035. /* These are not needed since we've redrawn the whole plot */
  1036.  
  1037.     while (XCheckMaskEvent(xwd->display, ExposureMask, event))
  1038.     ;
  1039. }
  1040.  
  1041. /*----------------------------------------------------------------------*\
  1042.  * ExposeCmd()
  1043.  *
  1044.  * Event handler routine for expose events.
  1045.  * These are "pure" exposures (no resize), so don't need to clear window.
  1046. \*----------------------------------------------------------------------*/
  1047.  
  1048. static void
  1049. ExposeCmd(PLStream *pls)
  1050. {
  1051.     XwDev *dev = (XwDev *) pls->dev;
  1052.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1053.  
  1054.     dbug_enter("ExposeCmd");
  1055.  
  1056. /* Return if plD_init_xw hasn't been called yet */
  1057.  
  1058.     if (dev == NULL) {
  1059.     plwarn("ExposeCmd: Illegal call -- driver uninitialized");
  1060.     return;
  1061.     }
  1062.  
  1063. /* Usual case: refresh window from pixmap */
  1064.  
  1065.     XSync(xwd->display, 0);
  1066.     if (dev->write_to_pixmap) {
  1067.     XCopyArea(xwd->display, dev->pixmap, dev->window, xwd->gc, 0, 0,
  1068.           dev->width, dev->height, 0, 0);
  1069.     XSync(xwd->display, 0);
  1070.     }
  1071.     else {
  1072.     plRemakePlot(pls);
  1073.     XFlush(xwd->display);
  1074.     }
  1075. }
  1076.  
  1077. /*----------------------------------------------------------------------*\
  1078.  * ResizeCmd()
  1079.  *
  1080.  * Event handler routine for resize events.
  1081.  * Note: this function is callable from the outside world.
  1082. \*----------------------------------------------------------------------*/
  1083.  
  1084. static void
  1085. ResizeCmd(PLStream *pls, PLWindow *window)
  1086. {
  1087.     XwDev *dev = (XwDev *) pls->dev;
  1088.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1089.  
  1090.     dbug_enter("ResizeCmd");
  1091.  
  1092. /* Return if plD_init_xw hasn't been called yet */
  1093.  
  1094.     if (dev == NULL) {
  1095.     plwarn("ResizeCmd: Illegal call -- driver uninitialized");
  1096.     return;
  1097.     }
  1098.  
  1099. /* Return if pointer to window not specified. */
  1100.  
  1101.     if (window == NULL) {
  1102.     plwarn("ResizeCmd: Illegal call -- window pointer uninitialized");
  1103.     return;
  1104.     }
  1105.  
  1106. /* Reset current window bounds */
  1107.  
  1108.     dev->width = window->width;
  1109.     dev->height = window->height;
  1110.  
  1111.     dev->xscale = (double) (dev->width-1) / (double) dev->init_width;
  1112.     dev->yscale = (double) (dev->height-1) / (double) dev->init_height;
  1113.  
  1114.     dev->xscale = dev->xscale * dev->xscale_init;
  1115.     dev->yscale = dev->yscale * dev->yscale_init;
  1116.  
  1117. /* Need to regenerate pixmap copy of window using new dimensions */
  1118.  
  1119.     if (dev->write_to_pixmap) {
  1120.     XSync(xwd->display, 0);
  1121.     XFreePixmap(xwd->display, dev->pixmap);
  1122.     CreatePixmap(pls);
  1123.     }
  1124.  
  1125. /* Now do a redraw using the new size */
  1126.  
  1127.     RedrawCmd(pls);
  1128. }
  1129.  
  1130. /*----------------------------------------------------------------------*\
  1131.  * RedrawCmd()
  1132.  *
  1133.  * Handles page redraw without resize (pixmap does not get reallocated).
  1134.  * Calling this makes sure all necessary housekeeping gets done.
  1135. \*----------------------------------------------------------------------*/
  1136.  
  1137. static void
  1138. RedrawCmd(PLStream *pls)
  1139. {
  1140.     XwDev *dev = (XwDev *) pls->dev;
  1141.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1142.  
  1143.     dbug_enter("RedrawCmd");
  1144.  
  1145. /* Return if plD_init_xw hasn't been called yet */
  1146.  
  1147.     if (dev == NULL) {
  1148.     plwarn("RedrawCmd: Illegal call -- driver uninitialized");
  1149.     return;
  1150.     }
  1151.  
  1152. /* Initialize & redraw to pixmap.  Then fake an expose. */
  1153.  
  1154.     if (dev->write_to_pixmap)
  1155.     dev->write_to_window = 0;
  1156.  
  1157.     XSync(xwd->display, 0);
  1158.     plD_bop_xw(pls);
  1159.     plRemakePlot(pls);
  1160.  
  1161.     XSync(xwd->display, 0);
  1162.     if (dev->write_to_pixmap) {
  1163.     XCopyArea(xwd->display, dev->pixmap, dev->window, xwd->gc, 0, 0,
  1164.           dev->width, dev->height, 0, 0);
  1165.     XSync(xwd->display, 0);
  1166.     }
  1167.     else {
  1168.     plRemakePlot(pls);
  1169.     XFlush(xwd->display);
  1170.     }
  1171.  
  1172.     dev->write_to_window = ! pls->db;
  1173. }
  1174.  
  1175. /*----------------------------------------------------------------------*\
  1176.  * CreatePixmapErrorHandler()
  1177.  *
  1178.  * Error handler used in CreatePixmap() to catch errors in allocating
  1179.  * storage for pixmap.  This way we can nicely substitute redraws for
  1180.  * pixmap copies if the server has insufficient memory.
  1181. \*----------------------------------------------------------------------*/
  1182.  
  1183. static unsigned char CreatePixmapStatus;
  1184.  
  1185. static int
  1186. CreatePixmapErrorHandler(Display *display, XErrorEvent *error)
  1187. {
  1188.     if (error->error_code == BadAlloc) {
  1189.     CreatePixmapStatus = error->error_code;
  1190.     }
  1191.     else
  1192.     fprintf(stderr, "Something bad just happened.\n");
  1193.  
  1194.     return(1);
  1195. }    
  1196.  
  1197. /*----------------------------------------------------------------------*\
  1198.  * CreatePixmap()
  1199.  *
  1200.  * This routine creates a pixmap, doing error trapping in case there
  1201.  * isn't enough memory on the server.
  1202. \*----------------------------------------------------------------------*/
  1203.  
  1204. static void
  1205. CreatePixmap(PLStream *pls)
  1206. {
  1207.     XwDev *dev = (XwDev *) pls->dev;
  1208.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1209.  
  1210.     int (*oldErrorHandler)();
  1211.  
  1212.     oldErrorHandler = XSetErrorHandler(CreatePixmapErrorHandler);
  1213.  
  1214.     CreatePixmapStatus = Success;
  1215. #ifdef DEBUG
  1216.     fprintf(stderr, "Creating pixmap of width %d, height %d, depth %d\n",
  1217.         dev->width, dev->height, xwd->depth);
  1218. #endif
  1219.     dev->pixmap = XCreatePixmap(xwd->display, dev->window,
  1220.                 dev->width, dev->height, xwd->depth);
  1221.     XSync(xwd->display, 0);
  1222.     if (CreatePixmapStatus != Success) {
  1223.     dev->write_to_pixmap = 0;
  1224.     dev->write_to_window = 1;
  1225.     pls->db = 0;
  1226.     fprintf(stderr, "\n\
  1227. Warning: pixmap could not be allocated (insufficient memory on server).\n\
  1228. Driver will redraw the entire plot to handle expose events.\n");
  1229.     }
  1230.  
  1231.     XSetErrorHandler(oldErrorHandler);
  1232. }
  1233.  
  1234. /*----------------------------------------------------------------------*\
  1235.  * Init_Colors()
  1236.  *
  1237.  * Does all color initialization.
  1238. \*----------------------------------------------------------------------*/
  1239.  
  1240. static void
  1241. Init_Colors(PLStream *pls)
  1242. {
  1243.     XwDev *dev = (XwDev *) pls->dev;
  1244.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1245.  
  1246.     Colormap default_map;
  1247.     PLColor fgcolor;
  1248.     int gslevbg, gslevfg;
  1249.     int visuals_matched = 0;
  1250.  
  1251.     dbug_enter("Init_Colors");
  1252.  
  1253. /* Grab default color map */
  1254.  
  1255.     default_map = DefaultColormap(xwd->display, xwd->screen);
  1256.  
  1257. /* Get visual info.
  1258.  * 
  1259.  * In order to safely use a visual other than that of the parent (which
  1260.  * hopefully is that returned by DefaultVisual), you must first find
  1261.  * (using XGetRGBColormaps) or create a colormap matching this visual and
  1262.  * then set the colormap window attribute in the XCreateWindow attributes
  1263.  * and valuemask arguments.  I don't do this right now, so this is turned
  1264.  * off by default.
  1265.  */
  1266.  
  1267. #if DEFAULT_VISUAL == 0
  1268.     {
  1269.     XVisualInfo vTemplate, *visualList;
  1270.  
  1271. /* Try for an 8 plane display, if unavailable go for the default */
  1272.  
  1273.     vTemplate.screen = xwd->screen;
  1274.     vTemplate.depth = 8;
  1275.  
  1276.     visualList = XGetVisualInfo( xwd->display,
  1277.                      VisualScreenMask | VisualDepthMask,
  1278.                      &vTemplate, &visuals_matched );
  1279.  
  1280.     if (visuals_matched) {
  1281.         xwd->visual = visualList->visual;    /* Choose first match. */
  1282.         xwd->depth = vTemplate.depth;
  1283.     }
  1284.     }
  1285. #endif
  1286.  
  1287.     if ( ! visuals_matched) {
  1288.     xwd->visual = DefaultVisual( xwd->display, xwd->screen );
  1289.     xwd->depth = DefaultDepth( xwd->display, xwd->screen );
  1290.     }
  1291.  
  1292. /*
  1293.  * Figure out if we have a color display or not.
  1294.  * Default is color IF the user hasn't specified and IF the output device is
  1295.  * not grayscale.  
  1296.  */
  1297.  
  1298.     if (pls->colorset)
  1299.     xwd->color = pls->color;
  1300.     else {
  1301.     pls->color = 1;
  1302.     xwd->color = ! pl_AreWeGrayscale(xwd->display);
  1303.     }
  1304.  
  1305. /*
  1306.  * Set background color.
  1307.  *
  1308.  * Background defaults to black on color screens, white on grayscale (many
  1309.  * grayscale monitors have poor contrast, and black-on-white looks better).
  1310.  */
  1311.  
  1312.     if ( ! xwd->color) {
  1313.     pls->cmap0[0].r = pls->cmap0[0].g = pls->cmap0[0].b = 0xFF;
  1314.     }
  1315.     gslevbg = ((long) pls->cmap0[0].r +
  1316.            (long) pls->cmap0[0].g +
  1317.            (long) pls->cmap0[0].b) / 3;
  1318.  
  1319. /*
  1320.  * Set foreground color.
  1321.  *
  1322.  * Used for grayscale output, since otherwise the plots can become nearly
  1323.  * unreadable (i.e. if colors get mapped onto grayscale values).  In this
  1324.  * case it becomes the grayscale level for all draws, and is taken to be
  1325.  * black if the background is light, and white if the background is dark.
  1326.  * Note that white/black allocations never fail.
  1327.  */
  1328.  
  1329.     if (gslevbg > 0x7F) 
  1330.     gslevfg = 0;
  1331.     else 
  1332.     gslevfg = 0xFF;
  1333.  
  1334.     fgcolor.r = fgcolor.g = fgcolor.b = gslevfg;
  1335.  
  1336.     PLColor_to_XColor(&fgcolor, &xwd->fgcolor);
  1337.  
  1338. /* If we're not on a color system, just allocate bg & fg then return */
  1339.  
  1340.     if ( ! xwd->color) {
  1341.     PLColor_to_XColor(&pls->cmap0[0], &xwd->cmap0[0]);
  1342.     XAllocColor(xwd->display, default_map, &xwd->cmap0[0]);
  1343.     XAllocColor(xwd->display, default_map, &xwd->fgcolor);
  1344.     return;
  1345.     }
  1346.  
  1347. /* Create custom color map and initialize cmap0 */
  1348.  
  1349.     if (plplot_ccmap) 
  1350.     Init_CustomCmap(pls);
  1351.     else 
  1352.     Init_DefaultCmap(pls);
  1353. }
  1354.  
  1355. /*----------------------------------------------------------------------*\
  1356.  * Init_CustomCmap()
  1357.  *
  1358.  * Initializes custom color map and all the cruft that goes with it.
  1359.  *
  1360.  * Assuming all color X displays do 256 colors, the breakdown is as follows:
  1361.  *
  1362.  * XWM_COLORS    Number of low "pixel" values to copy.  These are typically
  1363.  *        allocated first, thus are in use by the window manager. I
  1364.  *        copy them to reduce flicker.
  1365.  *
  1366.  * CMAP0_COLORS    Color map 0 entries.  I allocate these both in the default
  1367.  *        colormap and the custom colormap to reduce flicker.
  1368.  *
  1369.  * CMAP1_COLORS    Color map 1 entries.  There should be as many as practical
  1370.  *        available for smooth shading.  On the order of 100 is 
  1371.  *        pretty reasonable.  You don't really need all 256.  
  1372.  *
  1373.  * It's important to leave some extra colors unallocated for Tk.  In 
  1374.  * particular the palette tools require a fair amount.  I recommend leaving
  1375.  * at least 40 or so free.  
  1376. \*----------------------------------------------------------------------*/
  1377.  
  1378. static void
  1379. Init_CustomCmap(PLStream *pls)
  1380. {
  1381.     XwDev *dev = (XwDev *) pls->dev;
  1382.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1383.  
  1384.     Colormap default_map;
  1385.     XColor xwm_colors[MAX_COLORS];
  1386.     int i, j, npixels;
  1387.     unsigned long plane_masks[1];
  1388.     unsigned long pixel, pixels[MAX_COLORS];
  1389.  
  1390.     dbug_enter("Init_Colormap");
  1391.  
  1392. /* Grab default color map */
  1393.  
  1394.     default_map = DefaultColormap(xwd->display, xwd->screen);
  1395.  
  1396. /* Determine current default colors */
  1397.  
  1398.     for (i = 0; i < MAX_COLORS; i++) {
  1399.     xwm_colors[i].pixel = i;
  1400.     }
  1401.     XQueryColors(xwd->display, default_map, xwm_colors, MAX_COLORS);
  1402.  
  1403. /* Allocate cmap0 colors in the default colormap.
  1404.  * The custom cmap0 colors are later stored at the same pixel values.
  1405.  * This is a really cool trick to reduce the flicker when changing colormaps.
  1406.  */
  1407.  
  1408.     npixels = MIN(pls->ncol0, MAX_COLORS);
  1409.     while(1) {
  1410.     if (XAllocColorCells(xwd->display, default_map, False,
  1411.                  plane_masks, 0, pixels, npixels))
  1412.         break;
  1413.     npixels--;
  1414.     if (npixels == 0)
  1415.         plexit("couldn't allocate any colors");
  1416.     }
  1417.  
  1418.     xwd->ncol0 = npixels;
  1419.     for (i = 0; i < xwd->ncol0; i++) {
  1420.  
  1421.     PLColor_to_XColor(&pls->cmap0[i], &xwd->cmap0[i]);
  1422.  
  1423.     xwd->cmap0[i].pixel = pixels[i];
  1424.     XStoreColor(xwd->display, default_map, &xwd->cmap0[i]);
  1425.     }
  1426.     XAllocColor(xwd->display, default_map, &xwd->fgcolor);
  1427.  
  1428. /* Create color map */
  1429.  
  1430.     xwd->map = XCreateColormap( xwd->display, DefaultRootWindow(xwd->display),
  1431.                 xwd->visual, AllocNone );
  1432.  
  1433. /* Now allocate all colors so we can fill the ones we want to copy */
  1434.  
  1435.     npixels = MAX_COLORS;
  1436.     while(1) {
  1437.     if (XAllocColorCells(xwd->display, xwd->map, False,
  1438.                  plane_masks, 0, pixels, npixels))
  1439.         break;
  1440.     npixels--;
  1441.     if (npixels == 0)
  1442.         plexit("couldn't allocate any colors");
  1443.     }
  1444.  
  1445. /* Fill the low colors since those are in use by the window manager */
  1446.  
  1447.     for (i = 0; i < XWM_COLORS; i++) {
  1448.     XStoreColor(xwd->display, xwd->map, &xwm_colors[i]);
  1449.     pixels[xwm_colors[i].pixel] = 0;
  1450.     }
  1451.  
  1452. /* Fill the ones we will use in cmap0 */
  1453.  
  1454.     for (i = 0; i < xwd->ncol0; i++) {
  1455.     XStoreColor(xwd->display, xwd->map, &xwd->cmap0[i]);
  1456.     pixels[xwd->cmap0[i].pixel] = 0;
  1457.     }
  1458.  
  1459. /* Finally, if the colormap was saved by an external agent, see if there are
  1460.  * any differences from the current default map and save those!  A very cool
  1461.  * (or sick, depending on how you look at it) trick to get over some X and
  1462.  * Tk limitations.
  1463.  */
  1464.  
  1465.     if (sxwm_colors_set) {
  1466.     for (i = 0; i < MAX_COLORS; i++) {
  1467.         if ((xwm_colors[i].red != sxwm_colors[i].red) ||
  1468.         (xwm_colors[i].green != sxwm_colors[i].green) ||
  1469.         (xwm_colors[i].blue != sxwm_colors[i].blue) ) {
  1470.  
  1471.         if (pixels[i] != 0) {
  1472.             XStoreColor(xwd->display, xwd->map, &xwm_colors[i]);
  1473.             pixels[i] = 0;
  1474.         }
  1475.         }
  1476.     }
  1477.     }
  1478.  
  1479. /* Now free the ones we're not interested in */
  1480.  
  1481.     for (i = 0; i < npixels; i++) {
  1482.     if (pixels[i] != 0)
  1483.         XFreeColors(xwd->display, xwd->map, &pixels[i], 1, 0);
  1484.     }
  1485.  
  1486. /* Allocate colors in cmap 1 */
  1487.  
  1488.     npixels = MAX(2, MIN(CMAP1_COLORS, pls->ncol1));
  1489.     while(1) {
  1490.     if (XAllocColorCells(xwd->display, xwd->map, False,
  1491.                  plane_masks, 0, pixels, npixels))
  1492.         break;
  1493.     npixels--;
  1494.     if (npixels == 0)
  1495.         plexit("couldn't allocate any colors");
  1496.     }
  1497.  
  1498.     fprintf(stderr, "Allocated %d colors in cmap1\n", npixels);
  1499.     xwd->ncol1 = npixels;
  1500.     for (i = 0; i < xwd->ncol1; i++) {
  1501.     xwd->cmap1[i].pixel = pixels[i];
  1502.     }
  1503.  
  1504.     Cmap1Init(pls);
  1505. }
  1506.  
  1507. /*----------------------------------------------------------------------*\
  1508.  * Init_DefaultCmap()
  1509.  *
  1510.  * Initializes default color map and all the cruft that goes with it.
  1511.  * Have to severely limit number of colors in cmap1 otherwise TK won't
  1512.  * have enough.
  1513. \*----------------------------------------------------------------------*/
  1514.  
  1515. static void
  1516. Init_DefaultCmap(PLStream *pls)
  1517. {
  1518.     XwDev *dev = (XwDev *) pls->dev;
  1519.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1520.  
  1521.     Colormap default_map;
  1522.     int i, j, npixels;
  1523.     unsigned long plane_masks[1];
  1524.     unsigned long pixel, pixels[MAX_COLORS];
  1525.  
  1526.     dbug_enter("Init_DefaultCmap");
  1527.  
  1528. /* Grab default color map */
  1529.  
  1530.     xwd->map = DefaultColormap(xwd->display, xwd->screen);
  1531.  
  1532. /* Allocate and assign colors in cmap 0 */
  1533.  
  1534.     npixels = 16;
  1535.     while(1) {
  1536.     if (XAllocColorCells(xwd->display, xwd->map, False,
  1537.                  plane_masks, 0, pixels, npixels))
  1538.         break;
  1539.     npixels--;
  1540.     if (npixels == 0)
  1541.         plexit("couldn't allocate any colors");
  1542.     }
  1543.  
  1544.     xwd->ncol0 = npixels;
  1545.     for (i = 0; i < xwd->ncol0; i++) {
  1546.     xwd->cmap0[i].pixel = pixels[i];
  1547.     }
  1548.  
  1549.     Cmap0Init(pls);
  1550.  
  1551. /* Allocate colors in cmap 1 */
  1552.  
  1553.     npixels = MAX(2, MIN(CMAP1_COLORS, pls->ncol1));
  1554.     while(1) {
  1555.     if (XAllocColorCells(xwd->display, xwd->map, False,
  1556.                  plane_masks, 0, pixels, npixels))
  1557.         break;
  1558.     npixels--;
  1559.     if (npixels == 0)
  1560.         plexit("couldn't allocate any colors");
  1561.     }
  1562.  
  1563. /* Now free them all and start with a reduced number */
  1564.  
  1565.     XFreeColors(xwd->display, xwd->map, pixels, npixels, 0);
  1566.  
  1567.     npixels = MAX(npixels - 30, 10);
  1568.     while(1) {
  1569.     if (XAllocColorCells(xwd->display, xwd->map, False,
  1570.                  plane_masks, 0, pixels, npixels))
  1571.         break;
  1572.     npixels--;
  1573.     if (npixels == 0)
  1574.         plexit("couldn't allocate any colors");
  1575.     }
  1576.  
  1577.     fprintf(stderr, "Allocated %d colors in cmap1\n", npixels);
  1578.     xwd->ncol1 = npixels;
  1579.  
  1580. /* Don't assign pixels sequentially, to avoid strange problems with xor GC's */
  1581. /* Skipping by 2 seems to do the job best */
  1582.  
  1583.     for (j = i = 0; i < xwd->ncol1; i++) {
  1584.     while (pixels[j] == 0) 
  1585.         j++;
  1586.  
  1587.     xwd->cmap1[i].pixel = pixels[j];
  1588.     pixels[j] = 0;
  1589.  
  1590.     j += 2;
  1591.     if (j >= xwd->ncol1)
  1592.         j = 0;
  1593.     }
  1594.  
  1595.     Cmap1Init(pls);
  1596. }
  1597.  
  1598. /*----------------------------------------------------------------------*\
  1599.  * Cmap0Init()
  1600.  *
  1601.  * Initializes cmap 0
  1602. \*----------------------------------------------------------------------*/
  1603.  
  1604. static void
  1605. Cmap0Init(PLStream *pls)
  1606. {
  1607.     XwDev *dev = (XwDev *) pls->dev;
  1608.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1609.     int i;
  1610.  
  1611.     for (i = 0; i < xwd->ncol0; i++) {
  1612.     PLColor_to_XColor(&pls->cmap0[i], &xwd->cmap0[i]);
  1613.     XStoreColor(xwd->display, xwd->map, &xwd->cmap0[i]);
  1614.     }
  1615. }
  1616.  
  1617. /*----------------------------------------------------------------------*\
  1618.  * Cmap1Init()
  1619.  *
  1620.  * Initializes cmap 1
  1621. \*----------------------------------------------------------------------*/
  1622.  
  1623. static void
  1624. Cmap1Init(PLStream *pls)
  1625. {
  1626.     XwDev *dev = (XwDev *) pls->dev;
  1627.     XwDisplay *xwd = (XwDisplay *) dev->xwd;
  1628.  
  1629.     PLColor cmap1color;
  1630.     int i;
  1631.  
  1632.     for (i = 0; i < xwd->ncol1; i++) {
  1633.     plcol_interp(pls, &cmap1color, i, xwd->ncol1);
  1634.     PLColor_to_XColor(&cmap1color, &xwd->cmap1[i]);
  1635.     XStoreColor(xwd->display, xwd->map, &xwd->cmap1[i]);
  1636.     }
  1637. }
  1638.  
  1639. /*----------------------------------------------------------------------*\
  1640.  * void Colorcpy()
  1641.  *
  1642.  * Self-explanatory.
  1643. \*----------------------------------------------------------------------*/
  1644.  
  1645. static void
  1646. Colorcpy(XColor *xcolor1, XColor *xcolor2)
  1647. {
  1648.     xcolor1->red = xcolor2->red;
  1649.     xcolor1->green = xcolor2->green;
  1650.     xcolor1->blue = xcolor2->blue;
  1651.     xcolor1->pixel = xcolor2->pixel;
  1652. }
  1653.  
  1654. /*----------------------------------------------------------------------*\
  1655.  * void PLColor_to_XColor()
  1656.  *
  1657.  * Copies the supplied PLColor to an XColor, padding with bits as necessary
  1658.  * (a PLColor uses 8 bits for color storage, while an XColor uses 16 bits).
  1659.  * The argument types follow the same order as in the function name.
  1660. \*----------------------------------------------------------------------*/
  1661.  
  1662. #define ToXColor(a) (((0xFF & (a)) << 8) | (a))
  1663. #define ToPLColor(a) (((U_LONG) a) >> 8)
  1664.  
  1665. void
  1666. PLColor_to_XColor(PLColor *plcolor, XColor *xcolor)
  1667. {
  1668.     xcolor->red   = ToXColor(plcolor->r);
  1669.     xcolor->green = ToXColor(plcolor->g);
  1670.     xcolor->blue  = ToXColor(plcolor->b);
  1671.     xcolor->flags = DoRed | DoGreen | DoBlue;
  1672. }
  1673.  
  1674. /*----------------------------------------------------------------------*\
  1675.  * void PLColor_from_XColor()
  1676.  *
  1677.  * Copies the supplied XColor to a PLColor, stripping off bits as
  1678.  * necessary.  See the previous routine for more info.
  1679. \*----------------------------------------------------------------------*/
  1680.  
  1681. void
  1682. PLColor_from_XColor(PLColor *plcolor, XColor *xcolor)
  1683. {
  1684.     plcolor->r = ToPLColor(xcolor->red);
  1685.     plcolor->g = ToPLColor(xcolor->green);
  1686.     plcolor->b = ToPLColor(xcolor->blue);
  1687. }
  1688.  
  1689. /*----------------------------------------------------------------------*\
  1690.  * int pl_AreWeGrayscale(Display *display)
  1691.  *
  1692.  * Determines if we're using a monochrome or grayscale device.
  1693.  * gmf 11-8-91; Courtesy of Paul Martz of Evans and Sutherland. 
  1694. \*----------------------------------------------------------------------*/
  1695.  
  1696. int
  1697. pl_AreWeGrayscale(Display *display)
  1698. {
  1699. #if defined(__cplusplus) || defined(c_plusplus)
  1700. #define THING c_class
  1701. #else
  1702. #define THING class
  1703. #endif
  1704.  
  1705.     XVisualInfo *visuals;
  1706.     int nitems, i;
  1707.  
  1708.     /* get a list of info on the visuals available */
  1709.     visuals = XGetVisualInfo(display, 0, NULL, &nitems);
  1710.  
  1711.     /* check the list looking for non-monochrome visual classes */
  1712.     for (i = 0; i < nitems; i++)
  1713.     if ((visuals[i].THING != GrayScale) &&
  1714.         (visuals[i].THING != StaticGray))
  1715.         return (0);
  1716.  
  1717.     /* if we got this far, only StaticGray and GrayScale classes available */
  1718.     return (1);
  1719. }
  1720.  
  1721. /*----------------------------------------------------------------------*\
  1722.  * void PLX_save_colormap()
  1723.  *
  1724.  * Saves RGB components of given colormap.
  1725.  * Used in an ugly hack to get past some X11R5 and TK limitations.
  1726.  * This isn't guaranteed to work under all circumstances, but hopefully
  1727.  * in the future there will be a nicer way to accomplish the same thing.
  1728.  *
  1729.  * Note: I tried using XCopyColormapAndFree to do the same thing, but under
  1730.  * HPUX 9.01/VUE/X11R5 at least it doesn't preserve the previous read-only
  1731.  * color cell allocations made by Tk.  Is this a bug?  Have to look at the
  1732.  * source to find out.
  1733. \*----------------------------------------------------------------------*/
  1734.  
  1735. void
  1736. PLX_save_colormap(Display *display, Colormap colormap)
  1737. {
  1738.     int i;
  1739.  
  1740.     if ( ! plplot_ccmap)
  1741.     return;
  1742.  
  1743.     sxwm_colors_set = 1;
  1744.     for (i = 0; i < 256; i++) {
  1745.     sxwm_colors[i].pixel = i;
  1746.     }
  1747.     XQueryColors(display, colormap, sxwm_colors, 256);
  1748. /*
  1749.     printf("\nAt startup, default colors are: \n\n");
  1750.     for (i = 0; i < 256; i++) {
  1751.     printf(" i: %d,  pixel: %d,  r: %d,  g: %d,  b: %d\n",
  1752.            i, sxwm_colors[i].pixel,
  1753.            sxwm_colors[i].red, sxwm_colors[i].green, sxwm_colors[i].blue);
  1754.     }
  1755.  */
  1756. }
  1757.  
  1758. #else
  1759. int
  1760. pldummy_xwin()
  1761. {
  1762.     return 0;
  1763. }
  1764.  
  1765. #endif                /* PLD_xwin */
  1766.