xgraph.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:32k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* $Header: /usr/src/mash/repository/vint/xgraph/xgraph.c,v 1.3 1999/12/19 00:52:07 heideman Exp $ */
  2. /*
  3.  * xgraph - A Simple Plotter for X
  4.  *
  5.  * David Harrison
  6.  * University of California,  Berkeley
  7.  * 1986, 1987, 1988, 1989
  8.  *
  9.  * Please see copyright.h concerning the formal reproduction rights
  10.  * of this software.
  11.  *
  12.  * $Log: xgraph.c,v $
  13.  * Revision 1.3  1999/12/19 00:52:07  heideman
  14.  * warning suppresion, slightly different flot ahndling
  15.  *
  16.  * Revision 1.2  1999/12/03 23:17:46  heideman
  17.  * apply xgraph_no_animation.patch
  18.  *
  19.  * Revision 1.1.1.1  1999/12/03 23:15:52  heideman
  20.  * xgraph-12.0
  21.  *
  22.  */
  23. #ifndef lint
  24. static char rcsid[] = "$Id: xgraph.c,v 1.3 1999/12/19 00:52:07 heideman Exp $";
  25. #endif
  26. #include "copyright.h"
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include <pwd.h>
  30. #include <ctype.h>
  31. #include "xgraph.h"
  32. #include "xtb.h"
  33. #include "hard_devices.h"
  34. #include "params.h"
  35. extern void init_X();
  36. extern void do_error();
  37. #ifdef DO_DER
  38. extern void Bounds();
  39. #endif /* DO_DER */
  40. static char *tildeExpand();
  41. static void ReverseIt();
  42. static void Traverse();
  43. static int XErrHandler();
  44. NewDataSet PlotData[MAXSETS],
  45.            DataD1[MAXSETS],
  46.            DataD2[MAXSETS];
  47. XSegment *Xsegs[2]; /* Point space for X */
  48. /* Basic transformation stuff */
  49. double llx,
  50.         lly,
  51.         urx,
  52.         ury; /* Bounding box of all data */
  53. static XContext win_context = (XContext) 0;
  54. /* Other globally set defaults */
  55. Display *disp; /* Open display            */
  56. Visual *vis; /* Standard visual         */
  57. Colormap cmap; /* Standard colormap       */
  58. int     screen; /* Screen number           */
  59. int     depth; /* Depth of screen         */
  60. int numFiles = 0; /* Number of input files   */
  61. char *inFileNames[MAXSETS]; /* File names              */
  62. /* Total number of active windows */
  63. int Num_Windows = 0;
  64. char *Prog_Name;
  65. char *disp_name;
  66. main(argc, argv)
  67. int     argc;
  68. char   *argv[];
  69. /*
  70.  * This sets up the hard-wired defaults and reads the X defaults.
  71.  * The command line format is: xgraph [host:display].
  72.  */
  73. {
  74.     Window  primary,
  75.             NewWindow();
  76.     XEvent  theEvent;
  77.     LocalWin *win_info;
  78.     Cursor  zoomCursor;
  79.     FILE   *strm;
  80.     XColor  fg_color,
  81.             bg_color;
  82.     char    keys[MAXKEYS];
  83.     int     nbytes,
  84.             idx,
  85.             maxitems = 0,
  86.             flags;
  87.     int     errs = 0;
  88.     /* Open up new display */
  89.     Prog_Name = argv[0];
  90.     disp_name = "";
  91.     /* Parse the argument list looking for input files */
  92.     flags = ParseArgs(argc, argv, 0);
  93.     if (flags == D_XWINDOWS) {
  94. disp = XOpenDisplay(disp_name);
  95. if (!disp) {
  96.     (void) fprintf(stderr,
  97.    "%s: cannot open display `%s'n",
  98.    argv[0], disp_name);
  99.     exit(1);
  100. }
  101. XSetErrorHandler(XErrHandler);
  102.     }
  103.     /* Set up hard-wired defaults and allocate spaces */
  104.     InitSets(flags);
  105.     /* Read X defaults and override hard-coded defaults */
  106.     if (PM_INT("Output Device") == D_XWINDOWS)
  107. ReadDefaults();
  108.     /* Read the data into the data sets */
  109.     llx = lly = MAXFLOAT;
  110.     urx = ury = -MAXFLOAT;
  111.     for (idx = 0; idx < numFiles; idx++) {
  112. strm = fopen(inFileNames[idx], "r");
  113. if (!strm) {
  114.     (void) fprintf(stderr, "Warning:  cannot open file `%s'n",
  115.    inFileNames[idx]);
  116. }
  117. else {
  118.     if ((maxitems = ReadData(strm, inFileNames[idx])) < 0) {
  119. errs++;
  120.     }
  121.     (void) fclose(strm);
  122. }
  123.     }
  124.     if (!numFiles) {
  125. if ((maxitems = ReadData(stdin, (char *) 0)) < 0) {
  126.     errs++;
  127. }
  128.     }
  129.     if (errs) {
  130. (void) fprintf(stderr, "Problems found with input data.n");
  131. exit(1);
  132.     }
  133.     /* Parse the argument list to set options */
  134.     (void) ParseArgs(argc, argv, 1);
  135.     if (PM_BOOL("Animate")) param_set("TitleText",STR,"Animated X Graph");
  136.     if (maxitems == 0) {
  137. (void) fprintf(stderr, "Nothing to plot.n");
  138. exit(1);
  139.     }
  140.     Xsegs[0] = (XSegment *) Malloc((unsigned) (maxitems * sizeof(XSegment)));
  141.     Xsegs[1] = (XSegment *) Malloc((unsigned) (maxitems * sizeof(XSegment)));
  142.     /* Reverse Video Hack */
  143.     if (PM_BOOL("ReverseVideo"))
  144. ReverseIt();
  145.     hard_init();
  146.     if (PM_BOOL("Debug")) {
  147. if (PM_INT("Output Device") == D_XWINDOWS)
  148.     (void) XSynchronize(disp, 1);
  149. param_dump();
  150.     }
  151.     /* Logarithmic and bounding box computation */
  152.     flags = 0;
  153.     if (PM_BOOL("LogX"))
  154. flags |= LOG_X;
  155.     if (PM_BOOL("LogY"))
  156. flags |= LOG_Y;
  157.     if (PM_BOOL("StackGraph"))
  158. flags |= STK;
  159.     if (PM_BOOL("FitX"))
  160. flags |= FITX;
  161.     if (PM_BOOL("FitY"))
  162. flags |= FITY;
  163.     Traverse(flags);
  164.     /* Nasty hack here for bar graphs */
  165.     if (PM_BOOL("BarGraph")) {
  166. double  base;
  167. llx -= PM_DBL("BarWidth");
  168. urx += PM_DBL("BarWidth");
  169. base = PM_DBL("BarBase");
  170. if (base < lly)
  171.     lly = base;
  172. if (base > ury)
  173.     ury = base;
  174.     }
  175.     /* Create initial window */
  176.     if (PM_INT("Output Device") == D_XWINDOWS) {
  177.         double asp;
  178.         asp = 1.0;
  179. xtb_init(disp, screen, PM_PIXEL("Foreground"), PM_PIXEL("Background"),
  180.  PM_FONT("LabelFont"));
  181.         
  182. primary = NewWindow(Prog_Name,
  183.     PM_DBL("XLowLimit"), PM_DBL("YLowLimit"),
  184.     PM_DBL("XHighLimit"), PM_DBL("YHighLimit"),
  185.     asp,0);
  186. if (!primary) {
  187.     (void) fprintf(stderr, "Main window would not openn");
  188.     exit(1);
  189. }
  190. zoomCursor = XCreateFontCursor(disp, XC_sizing);
  191. fg_color = PM_COLOR("Foreground");
  192. bg_color = PM_COLOR("Background");
  193. XRecolorCursor(disp, zoomCursor, &fg_color, &bg_color);
  194. Num_Windows = 1;
  195. while (Num_Windows > 0) {
  196.     XNextEvent(disp, &theEvent);
  197.     if (xtb_dispatch(&theEvent) != XTB_NOTDEF)
  198. continue;
  199.     if (XFindContext(theEvent.xany.display,
  200.      theEvent.xany.window,
  201.      win_context, (caddr_t *) & win_info)) {
  202. /* Nothing found */
  203. continue;
  204.     }
  205.     switch (theEvent.type) {
  206.     case Expose:
  207. if (theEvent.xexpose.count <= 0) {
  208.     XWindowAttributes win_attr;
  209.     XGetWindowAttributes(disp, theEvent.xany.window, &win_attr);
  210.     win_info->dev_info.area_w = win_attr.width;
  211.     win_info->dev_info.area_h = win_attr.height;
  212.     init_X(win_info->dev_info.user_state);
  213.                     EraseData(win_info);
  214.     DrawWindow(win_info);
  215. }
  216. break;
  217.     case KeyPress:
  218. nbytes = XLookupString(&theEvent.xkey, keys, MAXKEYS,
  219.        (KeySym *) 0, (XComposeStatus *) 0);
  220. for (idx = 0; idx < nbytes; idx++) {
  221.     if (keys[idx] == CONTROL_D) {
  222. /* Delete this window */
  223. DelWindow(theEvent.xkey.window, win_info);
  224.     }
  225.     else if (keys[idx] == CONTROL_C) {
  226. /* Exit program */
  227. Num_Windows = 0;
  228.     }
  229.     else if (keys[idx] == 'h') {
  230. PrintWindow(theEvent.xany.window, win_info);
  231.     }
  232. }
  233. break;
  234.     case ButtonPress:
  235. /* Handle creating a new window */
  236. Num_Windows += HandleZoom(Prog_Name,
  237.   &theEvent.xbutton,
  238.   win_info, zoomCursor);
  239. break;
  240.     default:
  241. (void) fprintf(stderr, "Unknown event type: %xn",
  242.        theEvent.type);
  243. break;
  244.     }
  245. }
  246.     }
  247.     else {
  248. int     Device = PM_INT("Output Device");
  249. int     dflag = strcmp(PM_STR("Disposition"), "To Device") == 0;
  250. primary = NewWindow(Prog_Name,
  251.     PM_DBL("XLowLimit"), PM_DBL("YLowLimit"),
  252.     PM_DBL("XHighLimit"), PM_DBL("YHighLimit"),
  253.     1.0,0);
  254. do_hardcopy(Prog_Name, primary,
  255.     hard_devices[Device].dev_init,
  256.     dflag ? hard_devices[Device].dev_spec : 0,
  257.     PM_STR("FileOrDev"), (double) 19,
  258.     hard_devices[Device].dev_title_font,
  259.     hard_devices[Device].dev_title_size,
  260.     hard_devices[Device].dev_axis_font,
  261.     hard_devices[Device].dev_axis_size,
  262.     PM_BOOL("Document") * D_DOCU);
  263.     }
  264.     return 0;
  265. }
  266. #define BLACK_THRES 30000
  267. static void
  268. ReversePix(param_name)
  269. char   *param_name; /* Name of color parameter */
  270. /*
  271.  * Looks up `param_name' in the parameters database.  If found, the
  272.  * color is examined and judged to be either black or white based
  273.  * upon its red, green, and blue intensities.  The sense of the
  274.  * color is then reversed and reset to its opposite.
  275.  */
  276. {
  277.     params  val;
  278.     if (param_get(param_name, &val)) {
  279. if ((val.pixv.value.red < BLACK_THRES) &&
  280.     (val.pixv.value.green < BLACK_THRES) &&
  281.     (val.pixv.value.blue < BLACK_THRES)) {
  282.     /* Color is black */
  283.     param_reset(param_name, "white");
  284. }
  285. else {
  286.     /* Color is white */
  287.     param_reset(param_name, "black");
  288. }
  289.     }
  290.     else {
  291. (void) fprintf(stderr, "Cannot reverse color `%s'n", param_name);
  292.     }
  293. }
  294. static void
  295. ReverseIt()
  296. /*
  297.  * This routine attempts to implement reverse video.  It steps through
  298.  * all of the important colors in the parameters database and makes
  299.  * black white (and vice versa).
  300.  */
  301. {
  302.     int     i;
  303.     char    buf[1024];
  304.     for (i = 0; i < MAXATTR; i++) {
  305. (void) sprintf(buf, "%d.Color", i);
  306. ReversePix(buf);
  307.     }
  308.     ReversePix("Foreground");
  309.     ReversePix("Border");
  310.     ReversePix("ZeroColor");
  311.     ReversePix("Background");
  312. }
  313. static void
  314. Traverse(flags)
  315. int     flags; /* Options */
  316. /*
  317.  * Traverses through all of the data applying certain options to the
  318.  * data and computing the overall bounding box.  The flags are:
  319.  *   LOG_X Take the log of the X axis
  320.  *   LOG_Y Take the log of the Y axis
  321.  *   STK Stack coordinates.
  322.  *   FITX Fit x-coordinates from zero to one
  323.  *   FITY Fit y-coordinates from zero to one
  324.  */
  325. {
  326.     int     i,
  327.             j;
  328.     PointList *spot;
  329.     PointList *pspot;
  330.     static char *paramstr[] =
  331.     {
  332. "Cannot plot negative %s valuesn",
  333. "when the logarithmic option is selected.n",
  334. "Number of points in %d and %d don't match for stacking.n",
  335. "Point %d in %d and %d doesn't match for stacking.n",
  336. "Set %d has 0 %s.n"
  337.     };
  338.     if (flags & (FITX|FITY)) 
  339. for (i = 0; i < MAXSETS; i++) 
  340.     for (spot = PlotData[i].list; spot; spot = spot->next) {
  341. float minx, maxx, miny, maxy;
  342. minx = maxx = spot->xvec[0];
  343. maxy = miny = spot->yvec[0];
  344. for (j = 1; j < spot->numPoints; j++) {
  345.     minx = MIN(minx, spot->xvec[j]);
  346.     miny = MIN(miny, spot->yvec[j]);
  347.     maxx = MAX(maxx, spot->xvec[j]);
  348.     maxy = MAX(maxy, spot->yvec[j]);
  349. }
  350. maxx = maxx - minx;
  351. maxy = maxy - miny;
  352. if (maxx == 0.0) {
  353.     (void) fprintf(stderr, paramstr[3], i, "width");
  354.     maxx = 1.0;
  355. }
  356. if (maxy == 0.0) {
  357.     (void) fprintf(stderr, paramstr[3], i, "height");
  358.     maxy = 1.0;
  359. }
  360. switch (flags & (FITX|FITY)) {
  361. case FITX:
  362.     for (j = 0; j < spot->numPoints; j++) 
  363. spot->xvec[j] = (-minx + spot->xvec[j]) / maxx;
  364.     break;
  365. case FITY:
  366.     for (j = 0; j < spot->numPoints; j++) 
  367. spot->yvec[j] = (-miny + spot->yvec[j]) / maxy;
  368.     break;
  369. case FITX|FITY:
  370.     for (j = 0; j < spot->numPoints; j++) {
  371. spot->xvec[j] = (-minx + spot->xvec[j]) / maxx;
  372. spot->yvec[j] = (-miny + spot->yvec[j]) / maxy;
  373.     }
  374.     break;
  375. default:
  376.     abort();
  377. }
  378.     }
  379.     if (flags & STK)
  380. for (i = 1; i < MAXSETS; i++) {
  381.     for (spot = PlotData[i].list, pspot = PlotData[i - 1].list;
  382.  spot && pspot; spot = spot->next, pspot = pspot->next) {
  383. if (spot->numPoints != pspot->numPoints) {
  384.     (void) fprintf(stderr, paramstr[2], i - 1, i);
  385.     exit(1);
  386. }
  387. for (j = 0; j < spot->numPoints; j++) {
  388.     if (spot->xvec[j] != pspot->xvec[j]) {
  389. (void) fprintf(stderr, paramstr[3], j, i - 1, i);
  390. exit(1);
  391.     }
  392.     spot->yvec[j] += pspot->yvec[j];
  393. }
  394.     }
  395. }
  396.     for (i = 0; i < MAXSETS; i++) {
  397. for (spot = PlotData[i].list; spot; spot = spot->next) {
  398.     for (j = 0; j < spot->numPoints; j++) {
  399. if (flags & LOG_Y) {
  400.     if (spot->yvec[j] > 0.0) {
  401. spot->yvec[j] = log10(spot->yvec[j]);
  402.     }
  403.     else if (spot->yvec[j] == 0)
  404. spot->yvec[j] = 0.0;
  405.     else {
  406. (void) fprintf(stderr, paramstr[0], "Y");
  407. (void) fprintf(stderr, paramstr[1]);
  408. exit(1);
  409.     }
  410. }
  411. if (flags & LOG_X) {
  412.     if (spot->xvec[j] > 0.0) {
  413. spot->xvec[j] = log10(spot->xvec[j]);
  414.     }
  415.     else if (spot->xvec[j] == 0)
  416. spot->xvec[j] = 0.0;
  417.     else {
  418. (void) fprintf(stderr, paramstr[0], "X");
  419. (void) fprintf(stderr, paramstr[1]);
  420. exit(1);
  421.     }
  422. }
  423. /* Update global bounding box */
  424. if (spot->xvec[j] < llx)
  425.     llx = spot->xvec[j];
  426. if (spot->xvec[j] > urx)
  427.     urx = spot->xvec[j];
  428. if (spot->yvec[j] < lly)
  429.     lly = spot->yvec[j];
  430. if (spot->yvec[j] > ury)
  431.     ury = spot->yvec[j];
  432.     }
  433. }
  434.     }
  435. }
  436. /*
  437.  * Button handling functions
  438.  */
  439. /*ARGSUSED*/
  440. xtb_hret
  441. del_func(win, bval, info)
  442. Window  win; /* Button window    */
  443. int     bval; /* Button value     */
  444. char   *info; /* User information */
  445. /*
  446.  * This routine is called when the `Close' button is pressed in
  447.  * an xgraph window.  It causes the window to go away.
  448.  */
  449. {
  450.     Window  the_win = (Window) info;
  451.     LocalWin *win_info;
  452.     xtb_bt_set(win, 1, (char *) 0, 0);
  453.     if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
  454. if (win_info->flags & HARDCOPY_IN_PROGRESS) {
  455.     do_error("Can't close window whilenhardcopy dialog is posted.n");
  456.     xtb_bt_set(win, 0, (char *) 0, 0);
  457. }
  458. else {
  459.     DelWindow(the_win, win_info);
  460. }
  461.     }
  462.     return XTB_HANDLED;
  463. }
  464. /*ARGSUSED*/
  465. xtb_hret
  466. hcpy_func(win, bval, info)
  467. Window  win; /* Button Window    */
  468. int     bval; /* Button value     */
  469. char   *info; /* User Information */
  470. /*
  471.  * This routine is called when the hardcopy button is pressed
  472.  * in an xgraph window.  It causes the output dialog to be
  473.  * posted.
  474.  */
  475. {
  476.     Window  the_win = (Window) info;
  477.     LocalWin *win_info;
  478.     xtb_bt_set(win, 1, (char *) 0, 0);
  479.     if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
  480. win_info->flags |= HARDCOPY_IN_PROGRESS;
  481. PrintWindow(the_win, win_info);
  482. win_info->flags &= (~HARDCOPY_IN_PROGRESS);
  483.     }
  484.     xtb_bt_set(win, 0, (char *) 0, 0);
  485.     return XTB_HANDLED;
  486. }
  487. static
  488. /*ARGSUSED*/
  489.         xtb_hret
  490. abt_func(win, bval, info)
  491. Window  win; /* Button window    */
  492. int     bval; /* Button value     */
  493. char   *info; /* User information */
  494. {
  495.     static char *msg_fmt =
  496.     "Version %sn
  497. XGraph + Animation and Derivativesn
  498. Modification of code by David Harrisonn
  499. University of California, Berkeleyn
  500. (davidh@ic.Berkeley.EDU or n
  501. ...!ucbvax!ucbic!davidh)n
  502. Animation, differentiation, and a few othern
  503. new features added by Paul Walker,n
  504. National Center for Supercomputer Applicationsn
  505. and Univ. Illinois at U-C Dept of Physics.n
  506. Send comments or suggestions ton
  507. pwalker@ncsa.uiuc.edun";
  508.     static int active = 0;
  509.     char    msg_buf[1024];
  510.     if (!active) {
  511. active = 1;
  512. xtb_bt_set(win, 1, (char *) 0, 0);
  513. (void) sprintf(msg_buf, msg_fmt, VERSION_STRING);
  514. msg_box("XGraph", msg_buf);
  515. xtb_bt_set(win, 0, (char *) 0, 0);
  516. active = 0;
  517.     }
  518.     return XTB_HANDLED;
  519. }
  520. #ifdef DO_DER
  521. static
  522. /*ARGSUSED  PW*/
  523.         xtb_hret
  524. rew_func(win, bval, info)
  525. Window  win; /* Button window    */
  526. int     bval; /* Button value     */
  527. char   *info; /* User information */
  528. {
  529.     /* This routine added, Paul Walker, to rewind the animation and start
  530.        it over.  The only even moderatly tricky part is erasing the last
  531.        item, which still lives, and redrawing the axis.  I do it by just
  532.        copying the "Expose" information from the main routine. */
  533.     Window  the_win = (Window) info;
  534.     LocalWin *win_info;
  535.     /* Set animation to True */
  536.     param_set("Animate",BOOL,"on");
  537.     if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
  538.   XWindowAttributes win_attr;
  539.   XGetWindowAttributes(disp, the_win, &win_attr);
  540.   win_info->dev_info.area_w = win_attr.width;
  541.   win_info->dev_info.area_h = win_attr.height;
  542.   init_X(win_info->dev_info.user_state);
  543.           EraseData (win_info);
  544.   DrawWindow(win_info);
  545.     }
  546.     return XTB_HANDLED;
  547. }
  548. static
  549. /*ARGSUSED  PW*/
  550.         xtb_hret
  551. der_func(win, bval, info)
  552. Window  win; /* Button window    */
  553. int     bval; /* Button value     */
  554. char   *info; /* User information */
  555. {
  556.     /* This routine added, Paul Walker, to rewind the animation and start
  557.        it over.  The only even moderatly tricky part is erasing the last
  558.        item, which still lives, and redrawing the axis.  I do it by just
  559.        copying the "Expose" information from the main routine. */
  560.     Window  the_win = (Window) info;
  561.     Window new_win;
  562.     LocalWin *win_info;
  563.     double loX,loY,hiX,hiY,asp;
  564.     static char *msg_fmt =
  565.     "Version %sn
  566. Currently unable to displayn
  567. or calculate derivativesn
  568. higher than 2nd ordern";
  569.     static int active = 0;
  570.     char    msg_buf[1024];
  571.     XFindContext(disp, the_win, win_context, (caddr_t *) & win_info);
  572.     if (win_info->DOrder == 2) {
  573.       if (!active) {
  574. active = 1;
  575. xtb_bt_set(win, 1, (char *) 0, 0);
  576. (void) sprintf(msg_buf, msg_fmt, VERSION_STRING);
  577. msg_box("XGraph", msg_buf);
  578. xtb_bt_set(win, 0, (char *) 0, 0);
  579. active = 0;
  580.       }
  581.       return XTB_HANDLED;
  582.     }
  583.     Num_Windows += 1;
  584.     asp = 1.0;
  585.     Bounds(&loX,&loY,&hiX,&hiY,win_info->DOrder+1);
  586.     new_win = NewWindow("Derivatives", loX, loY, hiX, hiY, asp, 
  587.       win_info->DOrder+1);
  588.     if (!XFindContext(disp, new_win, win_context, (caddr_t *) & win_info)) {
  589.   XWindowAttributes win_attr;
  590.   XGetWindowAttributes(disp, new_win, &win_attr);
  591.   win_info->dev_info.area_w = win_attr.width;
  592.   win_info->dev_info.area_h = win_attr.height;
  593.   init_X(win_info->dev_info.user_state);
  594.           EraseData (win_info);
  595.   DrawWindow(win_info);
  596.     }
  597.     return XTB_HANDLED;
  598. }
  599. static
  600. /*ARGSUSED  PW*/
  601.         xtb_hret
  602. rpl_func(win, bval, info)
  603. Window  win; /* Button window    */
  604. int     bval; /* Button value     */
  605. char   *info; /* User information */
  606. {
  607.     /* Puts us back into static mode ... */
  608.     Window  the_win = (Window) info;
  609.     LocalWin *win_info;
  610.     /* Set animation to True */
  611.     param_set("Animate",BOOL,"off");
  612.     if (!XFindContext(disp, the_win, win_context, (caddr_t *) & win_info)) {
  613.   XWindowAttributes win_attr;
  614.   XGetWindowAttributes(disp, the_win, &win_attr);
  615.   win_info->dev_info.area_w = win_attr.width;
  616.   win_info->dev_info.area_h = win_attr.height;
  617.   init_X(win_info->dev_info.user_state);
  618.           EraseData (win_info);
  619.   DrawWindow(win_info);
  620.     }
  621.     return XTB_HANDLED;
  622. }
  623. /* End change PW */
  624. #endif /* DO_DER */
  625. #define NORMSIZE 600
  626. #define MINDIM 100
  627. Window
  628. NewWindow(progname, lowX, lowY, upX, upY, asp, DO)
  629. char   *progname; /* Name of program    */
  630. double  lowX,
  631.         lowY; /* Lower left corner  */
  632. double  upX,
  633.         upY; /* Upper right corner */
  634. double  asp; /* Aspect ratio       */
  635. int     DO;                     /* Derivative Order.  */
  636. /*
  637.  * Creates and maps a new window.  This includes allocating its
  638.  * local structure and associating it with the XId for the window.
  639.  * The aspect ratio is specified as the ratio of width over height.
  640.  */
  641. {
  642.     Window  new_window;
  643.     LocalWin *new_info;
  644.     static Cursor theCursor = (Cursor) 0;
  645.     XSizeHints sizehints;
  646.     XSetWindowAttributes wattr;
  647.     XWMHints wmhints;
  648.     XColor  fg_color,
  649.             bg_color;
  650.     int     geo_mask;
  651.     int     width,
  652.             height;
  653.     unsigned long wamask;
  654.     char    defSpec[120];
  655.     double  pad;
  656.     new_info = (LocalWin *) Malloc(sizeof(LocalWin));
  657.     new_info->DOrder = DO;
  658.     if (upX > lowX) {
  659. new_info->loX = lowX;
  660. new_info->hiX = upX;
  661.     }
  662.     else {
  663. new_info->loX = llx;
  664. new_info->hiX = urx;
  665.     }
  666.     if (upY > lowY) {
  667. new_info->loY = lowY;
  668. new_info->hiY = upY;
  669.     }
  670.     else {
  671. new_info->loY = lly;
  672. new_info->hiY = ury;
  673.     }
  674.     /* Increase the padding for aesthetics */
  675.     if (new_info->hiX - new_info->loX == 0.0) {
  676. pad = MAX(0.5, fabs(new_info->hiX / 2.0));
  677. new_info->hiX += pad;
  678. new_info->loX -= pad;
  679.     }
  680.     if (new_info->hiY - new_info->loY == 0) {
  681. pad = MAX(0.5, fabs(ury / 2.0));
  682. new_info->hiY += pad;
  683. new_info->loY -= pad;
  684.     }
  685.     /* Add 10% padding to bounding box (div by 20 yeilds 5%) */
  686.     pad = (new_info->hiX - new_info->loX) / 20.0;
  687.     new_info->loX -= pad;
  688.     new_info->hiX += pad;
  689.     pad = (new_info->hiY - new_info->loY) / 20.0;
  690.     new_info->loY -= pad;
  691.     new_info->hiY += pad;
  692.     /* Aspect ratio computation */
  693.     if (asp < 1.0) {
  694. height = NORMSIZE;
  695. width = ((int) (((double) NORMSIZE) * asp));
  696.     }
  697.     else {
  698. width = NORMSIZE;
  699. height = ((int) (((double) NORMSIZE) / asp));
  700.     }
  701.     height = MAX(MINDIM, height);
  702.     width = MAX(MINDIM, width);
  703.     if (PM_INT("Output Device") == D_XWINDOWS) {
  704. (void) sprintf(defSpec, "%dx%d+100+100", width, height);
  705. wamask = CWBackPixel | CWBorderPixel | CWColormap;
  706. wattr.background_pixel = PM_PIXEL("Background");
  707. wattr.border_pixel = PM_PIXEL("Border");
  708. wattr.colormap = cmap;
  709. sizehints.flags = PPosition | PSize;
  710. sizehints.x = sizehints.y = 100;
  711. sizehints.width = width;
  712. sizehints.height = height;
  713. geo_mask = XParseGeometry(PM_STR("Geometry"), 
  714.   &sizehints.x, &sizehints.y,
  715.   (unsigned int *) &sizehints.width,
  716.   (unsigned int *) &sizehints.height);
  717. if (geo_mask & (XValue|YValue)) 
  718.     sizehints.flags = (sizehints.flags & ~PPosition) | USPosition;
  719. if (geo_mask & (WidthValue | HeightValue)) 
  720.     sizehints.flags = (sizehints.flags & ~PSize) | USSize;
  721. new_window = XCreateWindow(disp, RootWindow(disp, screen),
  722.    sizehints.x, sizehints.y,
  723.    (unsigned int) sizehints.width,
  724.    (unsigned int) sizehints.height,
  725.    (unsigned int) PM_INT("BorderSize"),
  726.    depth, InputOutput, vis,
  727.    wamask, &wattr);
  728. if (new_window) {
  729.     xtb_frame cl_frame,
  730.             hd_frame,
  731.             ab_frame,
  732.                     rw_frame,
  733.                     rp_frame,
  734.                     dx_frame;
  735.     XStoreName(disp, new_window, progname);
  736.     XSetIconName(disp, new_window, progname);
  737.     wmhints.flags = InputHint | StateHint;
  738.     wmhints.input = True;
  739.     wmhints.initial_state = NormalState;
  740.     XSetWMHints(disp, new_window, &wmhints);
  741.     XSetWMNormalHints(disp, new_window, &sizehints);
  742.     /* Set device info */
  743.     set_X(new_window, &(new_info->dev_info));
  744.     if (!PM_BOOL("NoButton")) {
  745. /* Make buttons */
  746. xtb_bt_new(new_window, "Close", del_func,
  747.    (xtb_data) new_window, &cl_frame);
  748. new_info->close = cl_frame.win;
  749. XMoveWindow(disp, new_info->close, (int) BTNPAD, (int) BTNPAD);
  750. xtb_bt_new(new_window, "Hdcpy", hcpy_func,
  751.    (xtb_data) new_window, &hd_frame);
  752. new_info->hardcopy = hd_frame.win;
  753. XMoveWindow(disp, new_info->hardcopy,
  754.     (int) (BTNPAD + cl_frame.width + BTNINTER),
  755.     BTNPAD);
  756. xtb_bt_new(new_window, "About", abt_func,
  757.    (xtb_data) new_window, &ab_frame);
  758. new_info->about = ab_frame.win;
  759. XMoveWindow(disp, new_info->about,
  760.     (int) (BTNPAD + cl_frame.width + BTNINTER +
  761.    hd_frame.width + BTNINTER), BTNPAD);
  762. #ifdef DO_DER
  763.                 /* These buttons added PW */
  764. xtb_bt_new(new_window, "Anim", rew_func,
  765.    (xtb_data) new_window, &rw_frame);
  766. new_info->rewind = rw_frame.win;
  767. XMoveWindow(disp, new_info->rewind,
  768.     (int) (BTNPAD + cl_frame.width + BTNINTER +
  769.    hd_frame.width + BTNINTER +
  770.                            ab_frame.width + BTNINTER), BTNPAD);
  771. xtb_bt_new(new_window, "Replot", rpl_func,
  772.    (xtb_data) new_window, &rp_frame);
  773. new_info->replot = rp_frame.win;
  774. XMoveWindow(disp, new_info->replot,
  775.     (int) (BTNPAD + cl_frame.width + BTNINTER +
  776.    hd_frame.width + BTNINTER +
  777.                            ab_frame.width + BTNINTER +
  778.    rw_frame.width + BTNINTER), BTNPAD);
  779. xtb_bt_new(new_window, "Deriv", der_func,
  780.    (xtb_data) new_window, &dx_frame);
  781. new_info->deriv = dx_frame.win;
  782. XMoveWindow(disp, new_info->deriv,
  783.     (int) (BTNPAD + cl_frame.width + BTNINTER +
  784.    hd_frame.width + BTNINTER +
  785.                            ab_frame.width + BTNINTER +
  786.    rw_frame.width + BTNINTER +
  787.    rp_frame.width + BTNINTER), BTNPAD); 
  788. #endif /* DO_DER */
  789. new_info->flags = 0;
  790.     }
  791.     XSelectInput(disp, new_window,
  792.  ExposureMask | KeyPressMask | ButtonPressMask);
  793.     if (!theCursor) {
  794. theCursor = XCreateFontCursor(disp, XC_top_left_arrow);
  795. fg_color = PM_COLOR("Foreground");
  796. bg_color = PM_COLOR("Background");
  797. XRecolorCursor(disp, theCursor, &fg_color, &bg_color);
  798.     }
  799.     XDefineCursor(disp, new_window, theCursor);
  800.     if (!win_context) {
  801. win_context = XUniqueContext();
  802.     }
  803.     XSaveContext(disp, new_window, win_context, (caddr_t) new_info);
  804.     XMapWindow(disp, new_window);
  805.     return new_window;
  806. }
  807. else {
  808.     return (Window) 0;
  809. }
  810.     }
  811.     else {
  812. new_info->dev_info.area_h = 1.0;
  813. new_info->dev_info.area_w = 1.0;
  814. return ((Window) new_info);
  815.     }
  816. }
  817. DelWindow(win, win_info)
  818. Window  win; /* Window     */
  819. LocalWin *win_info; /* Local Info */
  820. /*
  821.  * This routine actually deletes the specified window and
  822.  * decrements the window count.
  823.  */
  824. {
  825.     xtb_data info;
  826.     XDeleteContext(disp, win, win_context);
  827.     xtb_bt_del(win_info->close, &info);
  828.     xtb_bt_del(win_info->hardcopy, &info);
  829.     xtb_bt_del(win_info->about, &info);
  830.     Free((char *) win_info);
  831.     XDestroyWindow(disp, win);
  832.     Num_Windows -= 1;
  833. }
  834. PrintWindow(win, win_info)
  835. Window  win; /* Window       */
  836. LocalWin *win_info; /* Local Info   */
  837. /*
  838.  * This routine posts a dialog asking about the hardcopy
  839.  * options desired.  If the user hits `OK',  the hard
  840.  * copy is performed.
  841.  */
  842. {
  843.     ho_dialog(win, Prog_Name, (char *) win_info);
  844. }
  845. static XRectangle boxEcho;
  846. static GC echoGC = (GC) 0;
  847. #define DRAWBOX 
  848. if (startX < curX) { 
  849.    boxEcho.x = startX; 
  850.    boxEcho.width = curX - startX; 
  851. } else { 
  852.    boxEcho.x = curX; 
  853.    boxEcho.width = startX - curX; 
  854. if (startY < curY) { 
  855.    boxEcho.y = startY; 
  856.    boxEcho.height = curY - startY; 
  857. } else { 
  858.    boxEcho.y = curY; 
  859.    boxEcho.height = startY - curY; 
  860. XDrawRectangles(disp, win, echoGC, &boxEcho, 1);
  861. #define TRANX(xval) 
  862. (((double) ((xval) - wi->XOrgX)) * wi->XUnitsPerPixel + wi->UsrOrgX)
  863. #define TRANY(yval) 
  864. (wi->UsrOppY - (((double) ((yval) - wi->XOrgY)) * wi->YUnitsPerPixel))
  865. int
  866. HandleZoom(progname, evt, wi, cur)
  867. char   *progname;
  868. XButtonPressedEvent *evt;
  869. LocalWin *wi;
  870. Cursor  cur;
  871. {
  872.     Window  win,
  873.             new_win;
  874.     Window  root_rtn,
  875.             child_rtn;
  876.     XEvent  theEvent;
  877.     int     startX,
  878.             startY,
  879.             curX,
  880.             curY,
  881.             newX,
  882.             newY,
  883.             stopFlag,
  884.             numwin = 0;
  885.     int     root_x,
  886.             root_y;
  887.     unsigned int mask_rtn;
  888.     double  loX,
  889.             loY,
  890.             hiX,
  891.             hiY,
  892.             asp;
  893.     win = evt->window;
  894.     if (XGrabPointer(disp, win, True,
  895.      (unsigned int) (ButtonPressMask | ButtonReleaseMask |
  896.    PointerMotionMask | PointerMotionHintMask),
  897.      GrabModeAsync, GrabModeAsync,
  898.      win, cur, CurrentTime) != GrabSuccess) {
  899. XBell(disp, 0);
  900. return 0;
  901.     }
  902.     if (echoGC == (GC) 0) {
  903. unsigned long gcmask;
  904. XGCValues gcvals;
  905. gcmask = GCForeground | GCFunction;
  906. gcvals.foreground = PM_PIXEL("ZeroColor") ^ PM_PIXEL("Background");
  907. gcvals.function = GXxor;
  908. echoGC = XCreateGC(disp, win, gcmask, &gcvals);
  909.     }
  910.     startX = evt->x;
  911.     startY = evt->y;
  912.     XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
  913.   &curX, &curY, &mask_rtn);
  914.     /* Draw first box */
  915.     DRAWBOX;
  916.     stopFlag = 0;
  917.     while (!stopFlag) {
  918. XNextEvent(disp, &theEvent);
  919. switch (theEvent.xany.type) {
  920. case MotionNotify:
  921.     XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
  922.   &newX, &newY, &mask_rtn);
  923.     /* Undraw the old one */
  924.     DRAWBOX;
  925.     /* Draw the new one */
  926.     curX = newX;
  927.     curY = newY;
  928.     DRAWBOX;
  929.     break;
  930. case ButtonRelease:
  931.     DRAWBOX;
  932.     XUngrabPointer(disp, CurrentTime);
  933.     stopFlag = 1;
  934.     if ((startX - curX != 0) && (startY - curY != 0)) {
  935. /* Figure out relative bounding box */
  936. loX = TRANX(startX);
  937. loY = TRANY(startY);
  938. hiX = TRANX(curX);
  939. hiY = TRANY(curY);
  940. if (loX > hiX) {
  941.     double  temp;
  942.     temp = hiX;
  943.     hiX = loX;
  944.     loX = temp;
  945. }
  946. if (loY > hiY) {
  947.     double  temp;
  948.     temp = hiY;
  949.     hiY = loY;
  950.     loY = temp;
  951. }
  952. /* physical aspect ratio */
  953. asp = ((double) ABS(startX - curX)) / 
  954.        ((double) ABS(startY - curY));
  955. new_win = NewWindow(progname, loX, loY, hiX, hiY, asp,
  956.                   wi->DOrder);
  957. if (new_win) {
  958.     numwin = 1;
  959. }
  960. else {
  961.     numwin = 0;
  962. }
  963.     }
  964.     else {
  965. numwin = 0;
  966.     }
  967.     break;
  968. default:
  969.     printf("unknown event: %dn", theEvent.xany.type);
  970.     break;
  971. }
  972.     }
  973.     return numwin;
  974. }
  975. #define RND(val) ((int) ((val) + 0.5))
  976. /*ARGSUSED*/
  977. void
  978. do_hardcopy(prog, info, init_fun, dev_spec, file_or_dev, maxdim,
  979.     ti_fam, ti_size, ax_fam, ax_size, doc_p)
  980. char   *prog; /* Program name for Xdefaults    */
  981. char   *info; /* Some state information        */
  982. int     (*init_fun) (); /* Hardcopy init function        */
  983. char   *dev_spec; /* Device specification (if any) */
  984. char   *file_or_dev; /* Filename or device spec       */
  985. double  maxdim; /* Maximum dimension in cm       */
  986. char   *ti_fam,
  987.        *ax_fam; /* Font family names             */
  988. double  ti_size,
  989.         ax_size; /* Font sizes in points          */
  990. int     doc_p; /* Documentation predicate       */
  991. /*
  992.  * This routine resets the function pointers to those specified
  993.  * by `init_fun' and causes a screen redisplay.  If `dev_spec'
  994.  * is non-zero,  it will be considered a sprintf string with
  995.  * one %s which will be filled in with `file_or_dev' and fed
  996.  * to popen(3) to obtain a stream.  Otherwise,  `file_or_dev'
  997.  * is considered to be a file and is opened for writing.  The
  998.  * resulting stream is fed to the initialization routine for
  999.  * the device.
  1000.  */
  1001. {
  1002.     LocalWin *curWin = (LocalWin *) info;
  1003.     LocalWin thisWin;
  1004.     FILE   *out_stream;
  1005.     char    buf[MAXBUFSIZE],
  1006.             err[MAXBUFSIZE],
  1007.             ierr[ERRBUFSIZE];
  1008.     char    tilde[MAXBUFSIZE * 10];
  1009.     int     final_w,
  1010.             final_h,
  1011.             flags;
  1012.     double  ratio;
  1013.     if (dev_spec) {
  1014. (void) sprintf(buf, dev_spec, file_or_dev);
  1015. out_stream = popen(buf, "w");
  1016. if (!out_stream) {
  1017.     sprintf(err, "Unable to issue command:n  %sn", buf);
  1018.     do_error(err);
  1019.     return;
  1020. }
  1021.     }
  1022.     else {
  1023. tildeExpand(tilde, file_or_dev);
  1024. out_stream = fopen(tilde, "w");
  1025. if (!out_stream) {
  1026.     sprintf(err, "Unable to open file `%s'n", tilde);
  1027.     do_error(err);
  1028.     return;
  1029. }
  1030.     }
  1031.     if (curWin != (LocalWin *) 0) {
  1032. thisWin = *curWin;
  1033. ratio = ((double) thisWin.dev_info.area_w) /
  1034.     ((double) thisWin.dev_info.area_h);
  1035.     }
  1036.     else
  1037. ratio = 1.0;
  1038.     if (thisWin.dev_info.area_w > thisWin.dev_info.area_h) {
  1039. final_w = RND(maxdim * 10000.0 * PM_DBL("Scale"));
  1040. final_h = RND(maxdim / ratio * 10000.0 * PM_DBL("Scale"));
  1041.     }
  1042.     else {
  1043. final_w = RND(maxdim * ratio * 10000.0 * PM_DBL("Scale"));
  1044. final_h = RND(maxdim * 10000.0 * PM_DBL("Scale"));
  1045.     }
  1046.     ierr[0] = '';
  1047.     flags = 0;
  1048.     if (doc_p)
  1049. flags |= D_DOCU;
  1050.     if ((*init_fun) (out_stream, final_w, final_h, ti_fam, ti_size,
  1051.      ax_fam, ax_size, flags, &(thisWin.dev_info), ierr)) {
  1052. DrawWindow(&thisWin);
  1053. if (thisWin.dev_info.xg_end) {
  1054.     thisWin.dev_info.xg_end(thisWin.dev_info.user_state);
  1055. }
  1056.     }
  1057.     else {
  1058. do_error(ierr);
  1059.     }
  1060.     if (dev_spec) {
  1061. (void) pclose(out_stream);
  1062.     }
  1063.     else {
  1064. (void) fclose(out_stream);
  1065.     }
  1066. }
  1067. static char *
  1068. tildeExpand(out, in)
  1069. char   *out; /* Output space for expanded file name */
  1070. char   *in; /* Filename with tilde                 */
  1071. /*
  1072.  * This routine expands out a file name passed in `in' and places
  1073.  * the expanded version in `out'.  It returns `out'.
  1074.  */
  1075. {
  1076.     char    username[50],
  1077.            *userPntr;
  1078.     struct passwd *userRecord;
  1079.     out[0] = '';
  1080.     /* Skip over the white space in the initial path */
  1081.     while ((*in == ' ') ||(*in == 't'))
  1082. in    ++;
  1083.     /* Tilde? */
  1084.     if (in[0] == TILDE) {
  1085. /* Copy user name into 'username' */
  1086. in    ++;
  1087. userPntr = &(username[0]);
  1088. while ((*in !='') &&(*in !='/')) {
  1089.     *(userPntr++) = *(in ++);
  1090. }
  1091. *(userPntr) = '';
  1092. /* See if we have to fill in the user name ourselves */
  1093. if (strlen(username) == 0) {
  1094.     userRecord = getpwuid(getuid());
  1095. }
  1096. else {
  1097.     userRecord = getpwnam(username);
  1098. }
  1099. if (userRecord) {
  1100.     /* Found user in passwd file.  Concatenate user directory */
  1101.     strcat(out, userRecord->pw_dir);
  1102. }
  1103.     }
  1104.     /* Concantenate remaining portion of file name */
  1105.     strcat(out, in);
  1106.     return out;
  1107. }
  1108. #define ERR_MSG_SIZE 2048
  1109. /*ARGSUSED*/
  1110. static int
  1111. XErrHandler(disp_ptr, evt)
  1112. Display *disp_ptr;
  1113. XErrorEvent *evt;
  1114. /*
  1115.  * Displays a nicely formatted message and core dumps.
  1116.  */
  1117. {
  1118.     char    err_buf[ERR_MSG_SIZE],
  1119.             mesg[ERR_MSG_SIZE],
  1120.             number[ERR_MSG_SIZE];
  1121.     char   *mtype = "XlibMessage";
  1122.     XGetErrorText(disp_ptr, evt->error_code, err_buf, ERR_MSG_SIZE);
  1123.     (void) fprintf(stderr, "X Error: %sn", err_buf);
  1124.     XGetErrorDatabaseText(disp_ptr, mtype, "MajorCode",
  1125.   "Request Major code %d", mesg, ERR_MSG_SIZE);
  1126.     (void) fprintf(stderr, mesg, evt->request_code);
  1127.     (void) sprintf(number, "%d", evt->request_code);
  1128.     XGetErrorDatabaseText(disp_ptr, "XRequest", number, "", err_buf,
  1129.   ERR_MSG_SIZE);
  1130.     (void) fprintf(stderr, " (%s)n", err_buf);
  1131.     abort();
  1132. }