home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xspringies / part02 < prev    next >
Text File  |  1993-04-28  |  44KB  |  1,628 lines

  1. Newsgroups: comp.sources.x
  2. From: dmd@gradient.cis.upenn.edu (Douglas DeCarlo)
  3. Subject: v19i054:  xspringies - it's a spring simulator...no, it's a game, Part02/16
  4. Message-ID: <1993Mar26.161149.9541@sparky.imd.sterling.com>
  5. X-Md4-Signature: 45f7042fdd357f684ce5d40f870b2a70
  6. Date: Fri, 26 Mar 1993 16:11:49 GMT
  7. Approved: chris@sparky.imd.sterling.com
  8.  
  9. Submitted-by: dmd@gradient.cis.upenn.edu (Douglas DeCarlo)
  10. Posting-number: Volume 19, Issue 54
  11. Archive-name: xspringies/part02
  12. Environment: X11
  13. Supersedes: xspringies: Volume 14, Issue 25-30
  14.  
  15. #!/bin/sh
  16. # to extract, remove the header and type "sh filename"
  17. if `test ! -s ./xdisp.c`
  18. then
  19. echo "writting ./xdisp.c"
  20. cat > ./xdisp.c << '\BARFOO\'
  21. /* xdisp.c -- Xlib display code for xspringies
  22.  * Copyright (C) 1991,1992  Douglas M. DeCarlo
  23.  *
  24.  * This file is part of XSpringies, a mass and spring simulation system for X
  25.  *
  26.  * XSpringies is free software; you can redistribute it and/or modify
  27.  * it under the terms of the GNU General Public License as published by
  28.  * the Free Software Foundation; either version 1, or (at your option)
  29.  * any later version.
  30.  *
  31.  * XSpringies is distributed in the hope that it will be useful,
  32.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  33.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  34.  * GNU General Public License for more details.
  35.  * 
  36.  * You should have received a copy of the GNU General Public License
  37.  * along with XSpringies; see the file COPYING.  If not, write to
  38.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  39.  *
  40.  */
  41.  
  42. #include "defs.h"
  43. #include <X11/Xlib.h>
  44. #include <X11/Xutil.h>
  45. #include <X11/keysym.h>
  46. #include <X11/cursorfont.h>
  47. #include <X11/Xos.h>
  48. #include "obj.h"
  49. #include "bitmap.h"
  50. #include "title.h"
  51. #include "bfbm.h"
  52.  
  53. /* Mode values */
  54. #define M_EDIT        0
  55. #define M_MASS        1
  56. #define M_SPRING    2
  57.  
  58. #define M_ACTION    3
  59.  
  60. /* Behavior function modes */
  61. #define M_BF        4
  62.  
  63. /* Button values */
  64. #define B_CENTER    0
  65. #define B_RESTLEN       1
  66. #define B_SELECTALL     2
  67. #define B_DELETE        3
  68. #define B_SAVESTATE    4
  69. #define B_RESSTATE    5
  70. #define B_DUPLICATE    6
  71. #define B_INSERTFILE    7
  72. #define B_LOADFILE    8
  73. #define B_SAVEFILE      9
  74. #define B_RESET            10
  75. #define B_QUIT        11
  76.  
  77. #define C_FIXEDMASS    0
  78. #define C_GRIDSNAP    1
  79. #define C_ADAPTIVE_STEP    2
  80. #define C_WTOP        4
  81. #define C_WLEFT        5
  82. #define C_WRIGHT    6
  83. #define C_WBOTTOM    7
  84. #define C_SHOWSPRING    8
  85.  
  86. #define S_MASS        0
  87. #define S_ELAS        1
  88. #define S_KSPR        2
  89. #define S_KDAMP        3
  90. #define S_GRAV        4
  91. #define S_GDIR        5
  92. #define S_VISC        6
  93. #define S_STICK        7
  94. #define S_TIMESTEP    8
  95. #define S_GRIDSNAP    9
  96. #define S_PRECISION    10
  97.  
  98. /* Number of previous mouse state saves */
  99. #define MOUSE_PREV    4
  100.  
  101. #define NAIL_SIZE    4
  102.  
  103. /* Number of milliseconds that each drawing takes (to prevent stops) */
  104. #define MIN_DIFFT    100
  105.  
  106. /* Default highlight color for color screen */
  107. #define HLCOLOR        "green"
  108.  
  109. /* Just in case someone has a 4.2 BSD system (you have my sympathy) */
  110. #ifndef FD_SET
  111. #define fd_set int
  112. #define FD_SET(fd,fdset) (*(fdset) |= (1 << (fd)))
  113. #define FD_CLR(fd,fdset) (*(fdset) &= ~(1 << (fd)))
  114. #define FD_ISSET(fd, fdset) (*(fdset) & (1 << (fd)))
  115. #define FD_ZERO(fdset) (*(fdset) = 0)
  116. #endif
  117.  
  118. /* X globals */
  119. Display *dpy;
  120. Window main_win, text_win, acts_win, draw_win;
  121. GC fggc, bggc, revgc, hlgc, selectboxgc;
  122. GC sdrawgc, drawgc, erasegc, selectgc, selectlinegc;
  123. Pixmap draw_pm, acts_pm, startup_pm;
  124. int fcolor, bcolor, hcolor;
  125. int main_wid, main_ht, draw_wid, draw_ht, planes, xfd;
  126.  
  127. /* Other globals */
  128. static int mode = M_EDIT, slid_dt_num, cur_force = 0, action = -1;
  129. static boolean quitting = FALSE;
  130. int cursor_pos = 0, spthick = 0;
  131.  
  132. /* Current and previous bounding box */
  133. int bb_ulx, bb_uly, bb_lrx, bb_lry;
  134. int bbo_ulx, bbo_uly, bbo_lrx, bbo_lry;
  135. boolean bboxing = TRUE;
  136.  
  137. /* Current mouse grab for spring */
  138. int static_spring = FALSE;
  139. int startx = 0, prevx = 0, starty = 0, prevy = 0;
  140.  
  141. t_state mst = {
  142.     1.0, 1.0,
  143.     1.0, 1.0,
  144.     FALSE, TRUE,
  145.     -1,
  146.     { -1, -1, -1, -1 },
  147.     { 10.0, 5.0, 10.0, 10000.0 },
  148.     { 0.0, 2.0, 0.0, 1.0 },
  149.     0.0, 0.0,
  150.     DEF_TSTEP, 1.0,
  151.     FALSE, FALSE,
  152.     20.0,
  153.     TRUE, TRUE, TRUE, TRUE
  154. }, initst, sst;
  155.  
  156. static double cur_grav_max[BF_NUM] = { 10000000.0, 10000000.0, 10000000.0, 10000000.0 };
  157. static double cur_grav_min[BF_NUM] = { 0.0, -10000000.0, -10000000.0, -10000000.0 };
  158. static double cur_misc_max[BF_NUM] = { 360.0, 10000000.0, 1000.0, 1000.0 };
  159. static double cur_misc_min[BF_NUM] = { -360.0, 0.0, 0.0, -0.0 };
  160.  
  161. /* Position of Gravity/Direction sliders */
  162. int force_liney, grav_slidx, grav_slidy, dir_slidx, dir_slidy;
  163.  
  164. /* Mouse recording */
  165. typedef struct {
  166.     int x, y;
  167.     unsigned long t;
  168. } mouse_info;
  169.  
  170. static mouse_info mprev[MOUSE_PREV];
  171. static int moffset = 0;
  172. static void mouse_event();
  173.  
  174. /* File operations globals */
  175. int file_op = F_NONE;
  176. char filename[MAXPATH];
  177.  
  178. /* clean_up: free all of the X objects created
  179.    like pixmaps and gcs
  180.    */
  181. static void clean_up()
  182. {
  183.     /* Free up X objects */
  184.     XFreePixmap(dpy, draw_pm);
  185.     XFreePixmap(dpy, acts_pm);
  186.     XFreePixmap(dpy, startup_pm);
  187.  
  188.     XFreeGC(dpy, fggc);
  189.     XFreeGC(dpy, bggc);
  190.     XFreeGC(dpy, revgc);
  191.     XFreeGC(dpy, hlgc);
  192.     XFreeGC(dpy, selectboxgc);
  193.  
  194.     XFreeGC(dpy, drawgc);
  195.     XFreeGC(dpy, sdrawgc);
  196.     XFreeGC(dpy, erasegc);
  197.     XFreeGC(dpy, selectgc);
  198.     XFreeGC(dpy, selectlinegc);
  199.     XCloseDisplay(dpy);
  200. }
  201.  
  202. /* fatal(msg): print out the message msg, clean up,
  203.    and exit
  204.    */
  205. void fatal(msg)
  206. char *msg;
  207. {
  208.     if (msg != NULL)
  209.       fprintf(stderr, msg);
  210.     clean_up();
  211.     exit(-1);
  212. }
  213.  
  214. void disp_filename(cur_reset)
  215. boolean cur_reset;
  216. {
  217.     char fbuff[MAXPATH + 256];
  218.     int offset;
  219.  
  220.     if (cur_reset)
  221.       cursor_pos = strlen(filename);
  222.  
  223.     switch (file_op) {
  224.       case F_NONE:
  225.     break;
  226.       case F_LOAD:
  227.     strcpy(fbuff, "Load file: ");
  228.     break;
  229.       case F_INSERT:
  230.     strcpy(fbuff, "Insert file: ");
  231.     break;
  232.       case F_SAVE:
  233.     strcpy(fbuff, "Save file: ");
  234.     break;
  235.     }
  236.  
  237.     XFillRectangle(dpy, text_win, bggc, 0, 0, draw_wid, T_HT);
  238.     if (file_op != F_NONE) {
  239.     int cur_offset;
  240.  
  241.     strncat(fbuff, filename, cursor_pos);
  242.  
  243.     if ((offset = strlen(fbuff) + 1 - (draw_wid - F_WID) / F_WID) < 0)
  244.       offset = 0;
  245.  
  246.     cur_offset = strlen(fbuff) - offset;
  247.  
  248.     strcat(fbuff, filename + cursor_pos);
  249.     XFillRectangle(dpy, text_win, hlgc, cur_offset * F_WID + F_WID/2, 1, F_WID, F_HT);
  250.     XDrawString(dpy, text_win, fggc, F_WID/2, F_HT, fbuff + offset, strlen(fbuff + offset));
  251.     }
  252.     XFlush(dpy);
  253. }
  254.  
  255. void file_error()
  256. {
  257.     XBell(dpy, 50);
  258. }
  259.  
  260. void reset_bbox()
  261. {
  262.     bb_ulx = bbo_ulx = bb_uly = bbo_uly = 0;
  263.     bb_lrx = bbo_lrx = draw_wid - 1;
  264.     bb_lry = bbo_lry = draw_ht - 1;
  265. }
  266.  
  267. void calc_bbox()
  268. {
  269.     int i, rad, bb_temp;
  270.     boolean first = TRUE, fixed;
  271.  
  272.     if (bboxing) {
  273.     if (static_spring) {
  274.         first = FALSE;
  275.         bb_ulx = MIN(startx, prevx);
  276.         bb_uly = MIN(starty, prevy);
  277.         bb_lrx = MAX(startx, prevx);
  278.         bb_lry = MAX(starty, prevy);
  279.     }
  280.     for (i = 0; i < num_mass; i++) {
  281.         if ((masses[i].status & S_ALIVE) || (i == 0 && springs[0].status & S_ALIVE)) {
  282.         fixed = (masses[i].status & S_FIXED) && !(masses[i].status & S_TEMPFIXED);
  283.         rad = fixed ? NAIL_SIZE : masses[i].radius;
  284.  
  285.         if (i == mst.center_id)
  286.           rad += 1;
  287.  
  288.         /* Make sure bounding box includes mass */
  289.         if (first) {
  290.             bb_ulx = COORD_X(masses[i].x - rad);
  291.             bb_uly = COORD_Y(masses[i].y + rad);
  292.             bb_lrx = COORD_X(masses[i].x + rad);
  293.             bb_lry = COORD_Y(masses[i].y - rad);
  294.             first = FALSE;
  295.         } else {
  296.             if ((bb_temp = COORD_X(masses[i].x - rad)) < bb_ulx)
  297.               bb_ulx = bb_temp;
  298.             if ((bb_temp = COORD_Y(masses[i].y + rad)) < bb_uly)
  299.               bb_uly = bb_temp;
  300.             if ((bb_temp = COORD_X(masses[i].x + rad)) > bb_lrx)
  301.               bb_lrx = bb_temp;
  302.             if ((bb_temp = COORD_Y(masses[i].y - rad)) > bb_lry)
  303.               bb_lry = bb_temp;
  304.         }
  305.         }
  306.     }
  307.  
  308.     /* Add bounding strip */
  309.     bb_ulx -= spthick + 1;
  310.     bb_uly -= spthick + 1;
  311.     bb_lrx += spthick + 1;
  312.     bb_lry += spthick + 1;
  313.  
  314.     /* Bound within screen */
  315.     if (bb_ulx < 0)
  316.       bb_ulx = 0;
  317.     if (bb_lrx < 0)
  318.       bb_lrx = 0;
  319.  
  320.     if (bb_uly < 0)
  321.       bb_uly = 0;
  322.     if (bb_lry < 0)
  323.       bb_lry = 0;
  324.     
  325.     if (bb_ulx >= draw_wid)
  326.       bb_ulx = draw_wid - 1;
  327.     if (bb_lrx >= draw_wid)
  328.       bb_lrx = draw_wid - 1;
  329.  
  330.     if (bb_uly >= draw_ht)
  331.       bb_uly = draw_ht - 1;
  332.     if (bb_lry >= draw_ht)
  333.       bb_lry = draw_ht - 1;
  334.  
  335.     /* Intersect with previous bbox, and set old box to new */
  336.     if (bbo_ulx < (bb_temp = bb_ulx))
  337.       bb_ulx = bbo_ulx;
  338.     bbo_ulx = bb_temp;
  339.  
  340.     if (bbo_uly < (bb_temp = bb_uly))
  341.       bb_uly = bbo_uly;
  342.     bbo_uly = bb_temp;
  343.  
  344.     if (bbo_lrx > (bb_temp = bb_lrx))
  345.       bb_lrx = bbo_lrx;
  346.     bbo_lrx = bb_temp;
  347.  
  348.     if (bbo_lry > (bb_temp = bb_lry))
  349.       bb_lry = bbo_lry;
  350.     bbo_lry = bb_temp;
  351.     }
  352. }
  353.  
  354. void draw_startup_picture()
  355. {
  356.     reset_bbox();
  357.  
  358.     /* Set up draw pixmap with startup picture */
  359.     XFillRectangle(dpy, draw_pm, erasegc, 0, 0, draw_wid, draw_ht);
  360.  
  361.     XCopyArea(dpy, startup_pm, draw_pm, drawgc, 0, 0, startup_width, startup_height, (draw_wid - startup_width) / 2, (draw_ht - startup_height) / 2);
  362. }
  363.  
  364. void redraw_system()
  365. {
  366.     static XArc *arcs = NULL, *selarcs = NULL, *circs = NULL, *selcircs = NULL;
  367.     static XSegment *segs = NULL, *selsegs = NULL;
  368.     static num_mass_alloc = 0, num_spring_alloc = 0;
  369.     XArc *cur_arc;
  370.     XSegment *cur_seg;
  371.     int numarcs, numselarcs, numcircs, numselcircs, numsegs, numselsegs;
  372.     int i, rad, num_spr;
  373.     boolean fixed;
  374.  
  375.     /* Draw springs */
  376.     numsegs = numselsegs = 0;
  377.     if (num_spring_alloc < num_spring) {
  378.     num_spring_alloc = num_spring;
  379.     segs = (XSegment *)xrealloc(segs, num_spring_alloc * sizeof(XSegment));
  380.     selsegs = (XSegment *)xrealloc(selsegs, num_spring_alloc * sizeof(XSegment));
  381.     }
  382.     num_spr = (mst.show_spring) ? num_spring : 1;
  383.  
  384.     for (i = 0; i < num_spr; i++) {
  385.     if (springs[i].status & S_ALIVE) {
  386.         if (springs[i].status & S_SELECTED) {
  387.         cur_seg = selsegs + numselsegs++;
  388.         } else {
  389.         cur_seg = segs + numsegs++;
  390.         }
  391.         
  392.         cur_seg->x1 = COORD_X(masses[springs[i].m1].x);
  393.         cur_seg->y1 = COORD_Y(masses[springs[i].m1].y);
  394.         cur_seg->x2 = COORD_X(masses[springs[i].m2].x);
  395.         cur_seg->y2 = COORD_Y(masses[springs[i].m2].y);
  396.     }
  397.     }
  398.     if (numsegs) {
  399.     XDrawSegments(dpy, draw_pm, sdrawgc, segs, numsegs);
  400.     }
  401.     if (numselsegs) {
  402.     XDrawSegments(dpy, draw_pm, erasegc, selsegs, numselsegs);
  403.     XDrawSegments(dpy, draw_pm, selectlinegc, selsegs, numselsegs);
  404.     }
  405.  
  406.     /* Draw masses */
  407.     numarcs = numselarcs = numcircs = numselcircs = 0;
  408.     if (num_mass_alloc < num_mass) {
  409.     num_mass_alloc = num_mass;
  410.     arcs = (XArc *)xrealloc(arcs, num_mass_alloc * sizeof(XArc));
  411.     selarcs = (XArc *)xrealloc(selarcs, num_mass_alloc * sizeof(XArc));
  412.     circs = (XArc *)xrealloc(circs, num_mass_alloc * sizeof(XArc));
  413.     selcircs = (XArc *)xrealloc(selcircs, num_mass_alloc * sizeof(XArc));
  414.     }
  415.  
  416.     for (i = 0; i < num_mass; i++) {
  417.     if (masses[i].status & S_ALIVE) {
  418.         /* Check if within bounds */
  419.         fixed = (masses[i].status & S_FIXED) && !(masses[i].status & S_TEMPFIXED);
  420.         rad = fixed ? NAIL_SIZE : masses[i].radius;
  421.  
  422.         if (COORD_X(masses[i].x + rad) >= 0 && COORD_X(masses[i].x - rad) <= draw_wid &&
  423.         COORD_Y(masses[i].y - rad) >= 0 && COORD_Y(masses[i].y + rad) <= draw_ht) {
  424.         /* Get cur_arc value based on if FIXED or SELECTED */
  425.         if (masses[i].status & S_SELECTED) {
  426.             if (fixed) {
  427.             cur_arc = selcircs + numselcircs++;
  428.             } else {
  429.             cur_arc = selarcs + numselarcs++;
  430.             }
  431.         } else {
  432.             if (fixed) {
  433.             cur_arc = circs + numcircs++;
  434.             } else {
  435.             cur_arc = arcs + numarcs++;
  436.             }
  437.         }
  438.  
  439.         cur_arc->x = COORD_X(masses[i].x) - rad;
  440.         cur_arc->y = COORD_Y(masses[i].y) - rad;
  441.         cur_arc->width = cur_arc->height = rad * 2 + 1;
  442.         cur_arc->angle1 = 0;
  443.         cur_arc->angle2 = 64 * 360;
  444.         }
  445.     }
  446.     }
  447.     /* Draw masses and nails */
  448.     if (numarcs) {
  449.     XFillArcs(dpy, draw_pm, drawgc, arcs, numarcs);
  450.     }
  451.     if (numselarcs) {
  452.     XFillArcs(dpy, draw_pm, erasegc, selarcs, numselarcs);
  453.     XFillArcs(dpy, draw_pm, selectgc, selarcs, numselarcs);
  454.     }
  455.     if (numcircs) {
  456.     XFillArcs(dpy, draw_pm, erasegc, circs, numcircs);
  457.     XDrawArcs(dpy, draw_pm, drawgc, circs, numcircs);
  458.     }
  459.     if (numselcircs) {
  460.     XFillArcs(dpy, draw_pm, erasegc, selcircs, numselcircs);
  461.     XDrawArcs(dpy, draw_pm, selectgc, selcircs, numselcircs);
  462.     }
  463.  
  464.     if (mst.center_id != -1) {
  465.     i = mst.center_id;
  466.  
  467.     rad = ((masses[i].status & S_FIXED) && !(masses[i].status & S_TEMPFIXED)) ? NAIL_SIZE : masses[i].radius;
  468.  
  469.     XDrawRectangle(dpy, draw_pm, drawgc, (int)(COORD_X(masses[i].x) - rad), (int)(COORD_Y(masses[i].y) - rad),
  470.                2 * rad + 1, 2 * rad + 1);
  471.     }
  472. }
  473.  
  474. void view_system()
  475. {
  476.     XCopyPlane(dpy, draw_pm, draw_win, fggc, bb_ulx, bb_uly, bb_lrx - bb_ulx + 1, bb_lry - bb_uly + 1, bb_ulx, bb_uly, 0x1);
  477. }
  478.  
  479. void view_subsystem(ulx, uly, wid, ht)
  480. int ulx, uly, wid, ht;
  481. {
  482.     if (ulx < 0) {
  483.     wid += ulx;
  484.     ulx = 0;
  485.     }
  486.     if (uly < 0) {
  487.     ht += uly;
  488.     uly = 0;
  489.     }
  490.     if (wid < 0 || ht < 0)
  491.       return;
  492.  
  493.     if (ulx + wid >= draw_wid)
  494.       wid -= (ulx + wid - draw_wid);
  495.     if (uly + ht >= draw_ht)
  496.       ht -= (uly + ht - draw_ht);
  497.  
  498.     if (wid < 0 || ht < 0)
  499.       return;
  500.  
  501.     XCopyPlane(dpy, draw_pm, draw_win, fggc, ulx, uly, wid, ht, ulx, uly, 0x1);
  502. }
  503.  
  504. void review_system(reset)
  505. boolean reset;
  506. {
  507.     if (reset) {
  508.     reset_bbox();
  509.     } else {
  510.     calc_bbox();
  511.     }
  512.  
  513.     /* Clear the old pixmap */
  514.     XFillRectangle(dpy, draw_pm, erasegc, bb_ulx, bb_uly, bb_lrx - bb_ulx + 1, bb_lry - bb_uly + 1);
  515.  
  516.     redraw_system();
  517.  
  518.     view_system();
  519.  
  520.     mouse_event(M_REDISPLAY, 0, 0, AnyButton, FALSE);
  521.     if (mst.adaptive_step) {
  522.     update_slider(slid_dt_num);
  523.     }
  524.     XFlush(dpy);
  525. }
  526.  
  527. void update_slidnum(w)
  528. int w;
  529. {
  530.     change_slider_parms(S_GRAV, &(mst.cur_grav_val[w]), cur_grav_max[w], cur_grav_min[w]);
  531.     change_slider_parms(S_GDIR, &(mst.cur_misc_val[w]), cur_misc_max[w], cur_misc_min[w]);
  532.  
  533.     update_slider(S_GRAV);
  534.     update_slider(S_GDIR);
  535. }
  536.  
  537. void redraw_names(w)
  538. int w;
  539. {
  540.     static char *grav_nam[] = { "Gravity", "Magnitude", "Magnitude", "Magnitude" };
  541.     static char *misc_nam[] = { "Direction", "Damping", "Exponent", "Exponent" };
  542.     int offset = 120;
  543.  
  544.     XDrawLine(dpy, acts_win, bggc, 4, force_liney-1, (BF_NUM)*(BF_SIZ+4)+5, force_liney-1);
  545.     XDrawLine(dpy, acts_win, bggc, 4, force_liney+BF_SIZ+6, (BF_NUM)*(BF_SIZ+4)+5, force_liney+BF_SIZ+6);
  546.     XFillRectangle(dpy, acts_win, bggc, grav_slidx + offset, grav_slidy - F_HT, B_WID - 1 - grav_slidx - offset,
  547.            dir_slidy + F_HT + 3 - grav_slidy);
  548.  
  549.     XDrawLine(dpy, acts_win, fggc, w*(BF_SIZ+4)+4, force_liney-1, (w+1)*(BF_SIZ+4)+5, force_liney-1);
  550.     XDrawLine(dpy, acts_win, fggc, w*(BF_SIZ+4)+4, force_liney+BF_SIZ+6, (w+1)*(BF_SIZ+4)+5, force_liney+BF_SIZ+6);
  551.     XDrawString(dpy, acts_win, fggc, grav_slidx + offset, grav_slidy, grav_nam[w], strlen(grav_nam[w]));
  552.     XDrawString(dpy, acts_win, fggc, dir_slidx + offset, dir_slidy, misc_nam[w], strlen(misc_nam[w]));
  553. }
  554.  
  555. void redisplay_widgets()
  556. {
  557.     XCopyPlane(dpy, acts_pm, acts_win, fggc, 0, 0, B_WID, B_HT, 0, 0, 0x1);
  558.  
  559.     redraw_names(cur_force);
  560.     
  561.     redraw_widgets(TRUE);
  562. }
  563.  
  564. int mass_radius(m)
  565. double m;
  566. {
  567.     int rad;
  568.  
  569.     rad = (int)(2 * log(4.0 * m + 1.0));
  570.  
  571.     if (rad < 1) rad = 1;
  572.     if (rad > 64) rad = 64;
  573.  
  574.     return rad + spthick/2;
  575. }
  576.  
  577. static void draw_mass(w, mx, my, m)
  578. Window w;
  579. int mx, my;
  580. double m;
  581. {
  582.     int rad;
  583.  
  584.     rad = mass_radius(m);
  585.  
  586.     XFillArc(dpy, w, fggc, mx - rad, my - rad, rad * 2 + 1, rad * 2 + 1, 0, 64 * 360);
  587. }
  588.  
  589. static void draw_spring(w, x1, y1, x2, y2)
  590. Window w;
  591. int x1, y1, x2, y2;
  592. {
  593.     XDrawLine(dpy, w, fggc, x1, y1, x2, y2);
  594. }
  595.  
  596. static void mouse_vel(mx, my)
  597. int *mx, *my;
  598. {
  599.     int i, totalx = 0, totaly = 0, scale = 0, dx, dy, dt;
  600.     int fudge = 256;
  601.     
  602.     for (i = 0; i < MOUSE_PREV - 1; i++) {
  603.     dx = mprev[(moffset + 2 + i) % MOUSE_PREV].x - mprev[(moffset + 1 + i) % MOUSE_PREV].x;
  604.     dy = mprev[(moffset + 2 + i) % MOUSE_PREV].y - mprev[(moffset + 1 + i) % MOUSE_PREV].y;
  605.     dt = mprev[(moffset + 2 + i) % MOUSE_PREV].t - mprev[(moffset + 1 + i) % MOUSE_PREV].t;
  606.     
  607.     if (dt) {
  608.         scale += 64 * i * i;
  609.         totalx += 64 * i * i * fudge * dx / dt;
  610.         totaly += 64 * i * i * fudge * dy / dt;
  611.     }
  612.     }
  613.  
  614.     if (scale) {
  615.     totalx /= scale;
  616.     totaly /= scale;
  617.     }
  618.  
  619.     *mx = totalx;
  620.     *my = totaly;
  621. }
  622.  
  623. void widget_notify(type, idno)
  624. int type, idno;
  625. {
  626.     int i;
  627.  
  628.     switch (type) {
  629.  
  630.       case O_BUTTON:
  631.     switch (idno) {
  632.       case B_CENTER:
  633.         set_center();
  634.         review_system(TRUE);
  635.         break;
  636.       case B_RESTLEN:
  637.         set_sel_restlen();
  638.         break;
  639.       case B_DELETE:
  640.         delete_selected();
  641.         review_system(TRUE);
  642.         break;
  643.       case B_SELECTALL:
  644.         select_all();
  645.         eval_selection();
  646.         review_system(TRUE);
  647.         break;
  648.       case B_SAVESTATE:
  649.         save_state();
  650.         sst = mst;
  651.         break;
  652.       case B_RESSTATE:
  653.         restore_state();
  654.         mst = sst;
  655.  
  656.         redisplay_widgets();
  657.         review_system(TRUE);
  658.         mouse_event(M_REDISPLAY, 0, 0, AnyButton, FALSE);
  659.         break;
  660.       case B_DUPLICATE:
  661.         duplicate_selected();
  662.         review_system(TRUE);
  663.         break;
  664.       case B_INSERTFILE:
  665.         file_op = F_INSERT;
  666.         disp_filename(TRUE);
  667.         break;
  668.       case B_LOADFILE:
  669.         file_op = F_LOAD;
  670.         disp_filename(TRUE);
  671.         break;
  672.       case B_SAVEFILE:
  673.         file_op = F_SAVE;
  674.         disp_filename(TRUE);
  675.         break;
  676.       case B_RESET:
  677.         delete_all();
  678.         mst = initst;
  679.         init_objects();
  680.  
  681.         redisplay_widgets();
  682.         review_system(TRUE);
  683.         mouse_event(M_REDISPLAY, 0, 0, AnyButton, FALSE);
  684.         break;
  685.       case B_QUIT:
  686.         quitting = TRUE;
  687.         break;
  688.     }
  689.     break;
  690.  
  691.       case O_MBUTTON:
  692.     if (idno >= M_BF && idno < M_BF + BF_NUM && mst.bf_mode[idno - M_BF] > 0) {
  693.         cur_force = idno - M_BF;
  694.         update_slidnum(cur_force);
  695.         redraw_names(cur_force);
  696.     }
  697.     break;
  698.  
  699.       case O_CHECKBOX:
  700.     switch (idno) {        
  701.       case C_FIXEDMASS:
  702.         for (i = 0; i < num_mass; i++) {
  703.         if (masses[i].status & S_SELECTED) {
  704.             if (mst.fix_mass) {
  705.             masses[i].status |= S_FIXED;
  706.             masses[i].status &= ~S_TEMPFIXED;
  707.             } else {
  708.             masses[i].status &= ~(S_FIXED | S_TEMPFIXED);
  709.             }
  710.         }
  711.         }
  712.         review_system(TRUE);
  713.         break;
  714.       case C_SHOWSPRING:
  715.         review_system(TRUE);
  716.         break;
  717.     }
  718.     break;
  719.  
  720.       case O_SLIDER:
  721.     switch (idno) {        
  722.       case S_MASS:
  723.         for (i = 0; i < num_mass; i++) {
  724.         if (masses[i].status & S_SELECTED) {
  725.             masses[i].mass = mst.cur_mass;
  726.             masses[i].radius = mass_radius(mst.cur_mass);
  727.         }
  728.         }
  729.         review_system(TRUE);
  730.         break;
  731.       case S_ELAS:
  732.         for (i = 0; i < num_mass; i++) {
  733.         if (masses[i].status & S_SELECTED)
  734.           masses[i].elastic = mst.cur_rest;
  735.         }
  736.         break;
  737.       case S_KSPR:
  738.         for (i = 0; i < num_spring; i++) {
  739.         if (springs[i].status & S_SELECTED)
  740.           springs[i].ks = mst.cur_ks;
  741.         }
  742.         break;
  743.       case S_KDAMP:
  744.         for (i = 0; i < num_spring; i++) {
  745.         if (springs[i].status & S_SELECTED)
  746.           springs[i].kd = mst.cur_kd;
  747.         }
  748.         break;
  749.     }
  750.     }
  751. }
  752.  
  753. static void mouse_event(type, mx, my, mbutton, shifted)
  754. int type;
  755. int mx, my, mbutton;
  756. int shifted;
  757. {
  758.     static int selection = -1, cur_button = 0;
  759.     static boolean active = FALSE, cur_shift = FALSE;
  760.  
  761.     /* Skip restarts when active or continuations when inactive */
  762.     if ((type != M_DOWN && !active) || (type == M_DOWN && active))
  763.       return;
  764.  
  765.     /* Do grid snapping operation */
  766.     if (mst.grid_snap && mode != M_EDIT) {
  767.     mx = ((mx + (int)mst.cur_gsnap / 2) / (int)mst.cur_gsnap) * (int)mst.cur_gsnap;
  768.     my = ((my + (int)mst.cur_gsnap / 2) / (int)mst.cur_gsnap) * (int)mst.cur_gsnap;
  769.     }
  770.  
  771.     switch (type) {
  772.       case M_REDISPLAY:
  773.     switch (mode) {
  774.       case M_EDIT:
  775.         switch (cur_button) {
  776.           case Button1:
  777.         if (selection < 0) {
  778.             XDrawRectangle(dpy, draw_win, selectboxgc, MIN(startx, prevx), MIN(starty, prevy),
  779.                    ABS(prevx - startx), ABS(prevy - starty));
  780.         }
  781.         break;
  782.           case Button2:
  783.         break;
  784.           case Button3:
  785.         break;
  786.         }
  787.         break;
  788.       case M_MASS:
  789.         draw_mass(draw_win, prevx, prevy, mst.cur_mass);
  790.         break;
  791.       case M_SPRING:
  792.         if (static_spring) {
  793.         startx = COORD_X(masses[selection].x);
  794.         starty = COORD_Y(masses[selection].y);
  795.         draw_spring(draw_win, startx, starty, prevx, prevy);
  796.         }
  797.         break;
  798.     }
  799.     break;
  800.  
  801.       case M_DOWN:
  802.     review_system(TRUE);
  803.     startx = prevx = mx;
  804.     starty = prevy = my;
  805.     cur_button = mbutton;
  806.     active = TRUE;
  807.     cur_shift = shifted;
  808.  
  809.     switch (mode) {
  810.       case M_EDIT:
  811.         switch (cur_button) {
  812.           case Button1:
  813.         {
  814.             boolean is_mass = FALSE;
  815.             selection = nearest_object(COORD_X(mx), COORD_Y(my), &is_mass);
  816.             
  817.             /* If not shift clicking, unselect all currently selected items */
  818.             if (!shifted) {
  819.             unselect_all();
  820.             review_system(TRUE);
  821.             }
  822.         }
  823.         break;
  824.           case Button2:
  825.           case Button3:
  826.         tempfixed_obj(TRUE);
  827.         break;
  828.         }
  829.         break;
  830.       case M_MASS:
  831.         draw_mass(draw_win, mx, my, mst.cur_mass);
  832.         break;
  833.       case M_SPRING:
  834.         {
  835.         boolean is_mass = TRUE;
  836.  
  837.         static_spring = (action == -1 || cur_button == Button3);
  838.  
  839.         selection = nearest_object(COORD_X(mx), COORD_Y(my), &is_mass);
  840.         if (selection >= 0 && is_mass) {
  841.             startx = COORD_X(masses[selection].x);
  842.             starty = COORD_Y(masses[selection].y);
  843.             if (static_spring) {
  844.             draw_spring(draw_win, startx, starty, prevx, prevy);
  845.             } else {
  846.             attach_fake_spring(selection);
  847.             move_fake_mass(COORD_X(mx), COORD_Y(my));
  848.             review_system(TRUE);
  849.             }
  850.         } else {
  851.             active = FALSE;
  852.         }
  853.         }
  854.         break;
  855.     }
  856.     break;
  857.  
  858.       case M_DRAG:
  859.     switch (mode) {
  860.       case M_EDIT:
  861.         switch (cur_button) {
  862.           case Button1:
  863.         if (selection < 0) {
  864.             view_subsystem(MIN(startx, prevx), MIN(starty, prevy), ABS(prevx - startx) + 1, ABS(prevy - starty) + 1);
  865.             prevx = mx;
  866.             prevy = my;
  867.             XDrawRectangle(dpy, draw_win, selectboxgc, MIN(startx, prevx), MIN(starty, prevy),
  868.                    ABS(prevx - startx), ABS(prevy - starty));
  869.         }
  870.         break;
  871.           case Button2:
  872.           case Button3:
  873.         /* Move objects relative to mouse */
  874.         translate_selobj(COORD_DX(mx - prevx), COORD_DY(my - prevy));
  875.         review_system(TRUE);
  876.         prevx = mx;
  877.         prevy = my;
  878.         break;
  879.         }        
  880.         break;
  881.       case M_MASS:
  882.         {
  883.         int rad = mass_radius(mst.cur_mass);
  884.         view_subsystem(prevx - rad, prevy - rad, rad * 2 + 1, rad * 2 + 1);
  885.         }
  886.         prevx = mx;
  887.         prevy = my;
  888.         draw_mass(draw_win, prevx, prevy, mst.cur_mass);
  889.         break;
  890.       case M_SPRING:
  891.         if (static_spring) {
  892.         view_subsystem(MIN(startx, prevx), MIN(starty, prevy), ABS(prevx - startx) + 1, ABS(prevy - starty) + 1);
  893.         prevx = mx;
  894.         prevy = my;
  895.         startx = COORD_X(masses[selection].x);
  896.         starty = COORD_Y(masses[selection].y);
  897.         draw_spring(draw_win, startx, starty, prevx, prevy);
  898.         } else {
  899.         move_fake_mass(COORD_X(mx), COORD_Y(my));
  900.         }
  901.         break;
  902.     }
  903.     break;
  904.  
  905.       case M_UP:
  906.     active = FALSE;
  907.     switch (mode) {
  908.       case M_EDIT:
  909.         switch (cur_button) {
  910.           case Button1:
  911.         if (selection < 0) {
  912.             select_objects(MIN(COORD_X(startx), COORD_X(mx)), MIN(COORD_Y(starty), COORD_Y(my)), 
  913.                    MAX(COORD_X(startx), COORD_X(mx)), MAX(COORD_Y(starty), COORD_Y(my)), cur_shift);
  914.             eval_selection();
  915.             review_system(TRUE);
  916.         } else {
  917.             boolean is_mass = FALSE;
  918.             
  919.             if ((selection = nearest_object(COORD_X(mx), COORD_Y(my), &is_mass)) >= 0) {
  920.             select_object(selection, is_mass, cur_shift);
  921.             eval_selection();
  922.             review_system(TRUE);
  923.             }
  924.         }
  925.         break;
  926.           case Button2:
  927.         tempfixed_obj(FALSE);
  928.         review_system(TRUE);
  929.         break;
  930.           case Button3:
  931.         {
  932.             int mvx, mvy;
  933.  
  934.             mouse_vel(&mvx, &mvy);
  935.  
  936.             changevel_selobj(COORD_DX(mvx), COORD_DY(mvy), FALSE);
  937.             tempfixed_obj(FALSE);
  938.             review_system(TRUE);
  939.         }
  940.         break;
  941.         }
  942.         break;
  943.       case M_MASS:
  944.         {
  945.         int newm;
  946.  
  947.         newm = create_mass();
  948.  
  949.         masses[newm].x = COORD_X((double)mx);
  950.         masses[newm].y = COORD_Y((double)my);
  951.         masses[newm].mass = mst.cur_mass;
  952.         masses[newm].radius = mass_radius(mst.cur_mass);
  953.         masses[newm].elastic = mst.cur_rest;
  954.         if (mst.fix_mass) masses[newm].status |= S_FIXED;
  955.  
  956.         review_system(TRUE);
  957.         }
  958.         break;
  959.  
  960.       case M_SPRING:
  961.         {
  962.         boolean is_mass = TRUE;
  963.         int start_sel = selection, newsel, endx, endy;
  964.  
  965.         if (!static_spring) {
  966.             kill_fake_spring();
  967.         }
  968.             
  969.         selection = nearest_object(COORD_X(mx), COORD_Y(my), &is_mass);
  970.         if ((static_spring || action == -1 || cur_button == Button1) && selection >= 0 && is_mass && selection != start_sel) {
  971.             startx = COORD_X(masses[start_sel].x);
  972.             starty = COORD_Y(masses[start_sel].y);
  973.             endx = COORD_X(masses[selection].x);
  974.             endy = COORD_Y(masses[selection].y);
  975.             
  976.             newsel = create_spring();
  977.             springs[newsel].m1 = start_sel;
  978.             springs[newsel].m2 = selection;
  979.             springs[newsel].ks = mst.cur_ks;
  980.             springs[newsel].kd = mst.cur_kd;
  981.             springs[newsel].restlen = sqrt((double)SQR(startx - endx) + (double)SQR(starty - endy));
  982.  
  983.             add_massparent(start_sel, newsel);
  984.             add_massparent(selection, newsel);
  985.         }
  986.  
  987.         review_system(TRUE);
  988.         }
  989.         break;
  990.     }
  991.     break;
  992.     }
  993.     XFlush(dpy);
  994. }
  995.  
  996. static boolean x_event()
  997. {
  998.     XEvent event, peek;
  999.     KeySym ks;
  1000.     char keybuf[1];
  1001.     
  1002.     if (quitting)
  1003.       return FALSE;
  1004.  
  1005.     XFlush(dpy);
  1006.  
  1007.     /* Get next event */
  1008.     if (XPending(dpy)) {
  1009.     XNextEvent(dpy, &event);
  1010.  
  1011.     switch (event.type) {
  1012.       case ButtonPress:
  1013.         if (!check_widgets(event.xbutton.window, event.xbutton.x, event.xbutton.y, event.xbutton.button, M_DOWN)) {
  1014.         /* Process button press event */
  1015.         if (event.xbutton.window == draw_win) {
  1016.             bzero(mprev, sizeof(mprev));
  1017.             mouse_event(M_DOWN, event.xbutton.x, event.xbutton.y, event.xbutton.button, event.xbutton.state & ShiftMask);
  1018.         } else if (event.xbutton.window == acts_win) {
  1019.             /* Show startup picture if clicked on xspringies logo */
  1020.             if (event.xbutton.x >= 4 && event.xbutton.x < 4 + title_width && event.xbutton.y >= 4 && event.xbutton.y < 4 + title_height) {
  1021.             draw_startup_picture();
  1022.             view_system();
  1023.             }
  1024.         }
  1025.         }
  1026.         break;
  1027.       case ButtonRelease:
  1028.         if (!check_widgets(event.xbutton.window, event.xbutton.x, event.xbutton.y, event.xbutton.button, M_UP)) {
  1029.         /* Process button release event */
  1030.         if (event.xbutton.window == draw_win) {
  1031.             mouse_event(M_UP, event.xbutton.x, event.xbutton.y, event.xbutton.button, FALSE);
  1032.         }
  1033.         }
  1034.         break;
  1035.       case MotionNotify:
  1036.         {
  1037.         Window mw = event.xmotion.window;
  1038.  
  1039.         /* Skip over other motion notify events for this window */
  1040.         while (XCheckWindowEvent(dpy, mw, PointerMotionMask, &event));
  1041.  
  1042.         if (event.xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) {
  1043.             if (!check_widgets(event.xmotion.window, event.xmotion.x, event.xmotion.y, 0, M_DRAG)) {
  1044.             /* Record mouse info */
  1045.             mprev[moffset].x = event.xmotion.x;
  1046.             mprev[moffset].y = event.xmotion.y;
  1047.             mprev[moffset].t = (unsigned long)(event.xmotion.time);
  1048.             moffset = (moffset + 1) % MOUSE_PREV;
  1049.  
  1050.             /* Process motion notify event */
  1051.             if (event.xbutton.window == draw_win) {
  1052.                 mouse_event(M_DRAG, event.xbutton.x, event.xbutton.y, AnyButton, FALSE);
  1053.             }
  1054.             }
  1055.         }
  1056.         }
  1057.         break;
  1058.  
  1059.       case KeyPress:
  1060.         keybuf[0] = '\0';
  1061.         XLookupString (&event.xkey, keybuf, sizeof(keybuf), &ks, NULL);
  1062.  
  1063.         /* Skip modifier key */
  1064.         if (IsModifierKey(ks) || ks == XK_Multi_key)
  1065.           break;
  1066.  
  1067.         key_press((int)(keybuf[0]), ks, event.xkey.window);
  1068.         break;
  1069.  
  1070.       case ConfigureNotify:
  1071.         {
  1072.         static boolean created = FALSE;
  1073.         int new_wid, new_ht;
  1074.  
  1075.         new_wid = event.xconfigure.width;
  1076.         new_ht = event.xconfigure.height;
  1077.  
  1078.         if (new_wid == main_wid && new_ht == main_ht)
  1079.           break;
  1080.  
  1081.         main_wid = new_wid;
  1082.         main_ht = new_ht;
  1083.  
  1084.         draw_wid = main_wid - B_WID - 1;
  1085.         draw_ht = main_ht - T_HT - 1;
  1086.  
  1087.         reset_bbox();
  1088.  
  1089.         if (created) {
  1090.             XFreePixmap(dpy, draw_pm);
  1091.             created = TRUE;
  1092.         }
  1093.         draw_pm = XCreatePixmap(dpy, draw_win, draw_wid, draw_ht, 1);
  1094.         review_system(TRUE);
  1095.  
  1096.         XMoveResizeWindow(dpy, text_win, B_WID + 1, draw_ht + 1, draw_wid, T_HT);
  1097.         XMoveResizeWindow(dpy, draw_win, B_WID + 1, 0, draw_wid, draw_ht);
  1098.         }
  1099.         break;
  1100.  
  1101.       case Expose:
  1102.         /* Skip over additional expose events */
  1103.         while (XCheckTypedEvent(dpy, Expose, &peek))
  1104.           event = peek;
  1105.         
  1106.         /* Generic expose event (redraw everything) */
  1107.         redisplay_widgets();
  1108.  
  1109.         view_system();
  1110.         mouse_event(M_REDISPLAY, 0, 0, AnyButton, FALSE);
  1111.  
  1112.         disp_filename(FALSE);
  1113.         break;
  1114.         
  1115.       default:
  1116.         break;
  1117.     }
  1118.     XFlush(dpy);
  1119.     } else {
  1120.     /* No events waiting */
  1121.     if (scan_flag) {
  1122.         static struct timeval tp, tpo;
  1123.         static struct timezone tzp;
  1124.         int difft;
  1125.  
  1126.         if (tpo.tv_sec == 0)
  1127.           gettimeofday(&tpo, &tzp);
  1128.  
  1129.         gettimeofday(&tp, &tzp);
  1130.         difft = (tp.tv_sec - tpo.tv_sec) * 1000000 + (tp.tv_usec - tpo.tv_usec);
  1131.  
  1132.         /* Do widget scanning buttons about 30 times / sec */
  1133.         if (difft > 30000) {
  1134.         tpo = tp;
  1135.         (void)check_widgets(acts_win, 0, 0, 0, M_HOLD);
  1136.         }
  1137.     } else if (action == -1) {
  1138.         /* Sleep until next X event */
  1139.         fd_set readfds;
  1140.         
  1141.         FD_ZERO(&readfds);
  1142.         FD_SET(xfd, &readfds);
  1143.         
  1144.         (void)select(xfd+1, &readfds, NULL, NULL, NULL);
  1145.     }
  1146.  
  1147.     if (action != -1 && animate_obj()) {
  1148.         static struct timeval tp, tpo;
  1149.         static struct timezone tzp;
  1150.         static int totaldiff = 0;
  1151.         static boolean started = FALSE;
  1152.         int difft;
  1153.  
  1154.         /* Get time the first time through */
  1155.         if (!started) {
  1156.         gettimeofday(&tp, &tzp);
  1157.         started = TRUE;
  1158.         }
  1159.         tpo = tp;
  1160.  
  1161.         gettimeofday(&tp, &tzp);
  1162.  
  1163.         difft = (tp.tv_sec - tpo.tv_sec) * 1000000 + (tp.tv_usec - tpo.tv_usec);
  1164.  
  1165.         if (difft < MIN_DIFFT)
  1166.           difft = MIN_DIFFT;
  1167.  
  1168.         if (difft > 0) {
  1169.         totaldiff += difft;
  1170.  
  1171.         /* Do updates over 30 frames per second (to make it smooth) */
  1172.         if (totaldiff > 20000) {
  1173.             totaldiff = 0;
  1174.             review_system(FALSE);
  1175.             XSync(dpy, False);
  1176.         }
  1177.         }
  1178.     }
  1179.     }
  1180.  
  1181.     return TRUE;
  1182. }
  1183.  
  1184. Pixmap get_pixmap(bits, width, height, inv)
  1185. char *bits;
  1186. int width, height;
  1187. boolean inv;
  1188. {
  1189.     int black, white;
  1190.  
  1191.     black = inv ? 1 : 0;
  1192.     white = inv ? 0 : 1;
  1193.  
  1194.     return XCreatePixmapFromBitmapData(dpy, main_win, bits, width, height, white, black, 1);
  1195. }
  1196.  
  1197. unsigned long GetColor(cname, cmap)
  1198. char *cname;
  1199. Colormap cmap;
  1200. {
  1201.     /* Color stuff */
  1202.     XColor xc;
  1203.  
  1204.     if (XParseColor(dpy, cmap, cname, &xc) == 0) {
  1205.     fprintf(stderr, "Unknown color: %s\n", cname);
  1206.     exit(-1);
  1207.     } else {
  1208.     if (XAllocColor(dpy, cmap, &xc) == 0) {
  1209.         fprintf(stderr, "Cannot allocate color: %s\n", cname);
  1210.         exit(-1);
  1211.     }
  1212.     }
  1213.  
  1214.     return xc.pixel;
  1215. }
  1216.  
  1217. static void init_x(argc, argv, displayname, geometry, fgcolor, bgcolor, hlcolor)
  1218. int argc;
  1219. char *argv[];
  1220. char *displayname, *geometry, *fgcolor, *bgcolor, *hlcolor;
  1221. {
  1222.     XGCValues gcv, gcmv;
  1223.     XSetWindowAttributes xswa;
  1224.     XSizeHints hints;
  1225.     XFontStruct *font;
  1226.     Cursor cross;
  1227.     Colormap cmap;
  1228.     Pixmap icon_p;
  1229.     Visual *vis;
  1230.     int scn;
  1231.     int mask = 0;
  1232.  
  1233.     /* Open display */
  1234.     if ((dpy = XOpenDisplay(displayname)) == NULL) {
  1235.     fprintf(stderr, "Could not open display\n");
  1236.     exit(-1);
  1237.     }
  1238.  
  1239.     /* Get screen and colors */
  1240.     scn = DefaultScreen(dpy);
  1241.     planes = DisplayPlanes(dpy, scn);
  1242.     cmap = DefaultColormap(dpy, scn);
  1243.     vis = DefaultVisual(dpy, scn);
  1244.     xfd = ConnectionNumber(dpy);
  1245.  
  1246.     if (hlcolor == NULL) {
  1247.     if (vis->class == StaticGray || vis->class == GrayScale) {
  1248.         hlcolor = fgcolor;
  1249.     } else {
  1250.         XColor xc;
  1251.  
  1252.         if (XParseColor(dpy, cmap, HLCOLOR, &xc) == 0) {
  1253.         hlcolor = fgcolor;
  1254.         } else {
  1255.         hlcolor = HLCOLOR;
  1256.         }
  1257.     }
  1258.     }
  1259.  
  1260.     fcolor = GetColor(fgcolor, cmap);
  1261.     bcolor = GetColor(bgcolor, cmap);
  1262.     hcolor = GetColor(hlcolor, cmap);
  1263.  
  1264.     /* Set up main window */
  1265.     main_wid = hints.width = M_WID + 2;
  1266.     hints.min_width = B_WID * 2;
  1267.     main_ht = hints.height = hints.min_height = M_HT + 2;
  1268.     hints.flags = PSize | PMinSize;
  1269.  
  1270.     /* Get geometry info */
  1271.     if (geometry != NULL) {
  1272.     hints.x = hints.y = 0;
  1273.  
  1274.     if (mask = XParseGeometry(geometry, &(hints.x), &(hints.y), &(hints.width), &(hints.height))) {
  1275.         hints.flags |= ((mask & (XValue | YValue)) ? USPosition: PPosition) |
  1276.           ((mask & (WidthValue | HeightValue)) ? USSize : PSize);
  1277.  
  1278.         if (hints.width < hints.min_width)
  1279.           hints.width = hints.min_width;
  1280.         if (hints.height < hints.min_height)
  1281.           hints.height = hints.min_height;
  1282.     }
  1283.     }
  1284.  
  1285.     /* Create main window */
  1286.     main_win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), hints.x, hints.y, hints.width, hints.height, 1, fcolor, bcolor);
  1287.  
  1288.     /* Fix for open-look wm (thanks to Brian.Warkentine@Eng.Sun.COM) */
  1289.     {
  1290.         XWMHints wmhints;
  1291.         XWindowAttributes xwa;
  1292.  
  1293.     wmhints.flags = InputHint;
  1294.     wmhints.input = True;
  1295.     (void) XGetWindowAttributes(dpy, main_win, &xwa);
  1296.     XSelectInput(dpy, main_win, xwa.all_event_masks | KeyPressMask);
  1297.     XSetWMHints(dpy, main_win, &wmhints);
  1298.     }
  1299.  
  1300.     icon_p = XCreatePixmapFromBitmapData(dpy, DefaultRootWindow(dpy), icon_bits, icon_width, icon_height, 1, 0, planes);
  1301.     XSetStandardProperties(dpy, main_win, "XSpringies", "XSpringies", icon_p, argv, argc, &hints);
  1302.  
  1303.     if (mask)
  1304.       XSetNormalHints(dpy, main_win, &hints);
  1305.  
  1306.     /* Map main window to display */
  1307.     XMapWindow(dpy, main_win);
  1308.  
  1309.     XFlush(dpy);
  1310.     XSync(dpy, False);
  1311.  
  1312.     {
  1313.     Window tmp_win;
  1314.     int xpos, ypos;
  1315.     unsigned int bw, dep;
  1316.     
  1317.     XGetGeometry(dpy, main_win, &tmp_win, &xpos, &ypos, &main_wid, &main_ht, &bw, &dep);
  1318.     }
  1319.  
  1320.     /* Make subwindows */
  1321.     acts_win = XCreateSimpleWindow(dpy, main_win, 0, 0, B_WID, B_HT, 1, fcolor, bcolor);
  1322.  
  1323.     draw_wid = main_wid - B_WID - 1;
  1324.     draw_ht = main_ht - T_HT - 1;
  1325.     draw_win = XCreateSimpleWindow(dpy, main_win, B_WID + 1, 0, draw_wid, draw_ht, 1, fcolor, bcolor);
  1326.     text_win = XCreateSimpleWindow(dpy, main_win, B_WID + 1, draw_ht + 1, draw_wid, T_HT, 1, fcolor, bcolor);
  1327.  
  1328.     /* Make pixmaps for drawing and actions areas (to make redraw trivial) */
  1329.     draw_pm = XCreatePixmap(dpy, draw_win, draw_wid, draw_ht, 1);
  1330.  
  1331.     acts_pm = XCreatePixmap(dpy, acts_win, B_WID, B_HT, 1);
  1332.  
  1333.     /* Get a font */
  1334.     if ((font = XLoadQueryFont(dpy, F_NAME)) == NULL) {
  1335.     fprintf(stderr, "Could not load font: %s\n", F_NAME);
  1336.     exit(-1);
  1337.     }
  1338.  
  1339.     /* Create GCs */
  1340.     gcmv.font = gcv.font = font->fid;
  1341.     gcmv.plane_mask = gcv.plane_mask = 1;
  1342.     gcmv.line_width = spthick;
  1343.  
  1344.     gcmv.foreground = 1;
  1345.     gcmv.background = 0;
  1346.  
  1347.     gcv.foreground = bcolor;
  1348.     gcv.background = hcolor;
  1349.     revgc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont, &gcv);
  1350.  
  1351.     gcv.foreground = hcolor;
  1352.     gcv.background = bcolor;
  1353.     hlgc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont, &gcv);
  1354.  
  1355.     gcv.foreground = fcolor;
  1356.     drawgc = XCreateGC(dpy, draw_pm, GCForeground | GCBackground | GCFont, &gcmv);
  1357.     sdrawgc = XCreateGC(dpy, draw_pm, GCForeground | GCBackground | GCFont | GCLineWidth, &gcmv);
  1358.     fggc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont, &gcv);
  1359.  
  1360.     {
  1361.     static char stipple_bits[] = { 0x01, 0x02 };
  1362.     static char dot_line[2] = { 1, 1 };
  1363.     Pixmap stip;
  1364.  
  1365.     stip = XCreateBitmapFromData(dpy, main_win, stipple_bits, 2, 2);
  1366.     gcmv.stipple = gcv.stipple = stip;
  1367.     gcmv.fill_style = gcv.fill_style = FillStippled;
  1368.     
  1369.     gcmv.line_style = gcv.line_style = LineOnOffDash;
  1370.     selectgc = XCreateGC(dpy, draw_pm, GCForeground | GCBackground | GCFont | GCFillStyle | GCStipple, &gcmv);
  1371.      selectlinegc = XCreateGC(dpy, draw_pm, GCForeground | GCBackground | GCFont | GCLineStyle | GCLineWidth, &gcmv);
  1372.  
  1373.     gcv.foreground = hcolor;
  1374.  
  1375.     if (hcolor != fcolor && hcolor != bcolor) {
  1376.         selectboxgc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont, &gcv);
  1377.     } else {
  1378.         selectboxgc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont | GCLineStyle, &gcv);
  1379.         XSetDashes(dpy, selectboxgc, 0, dot_line, 2);
  1380.     }        
  1381.  
  1382.     XSetDashes(dpy, selectlinegc, 0, dot_line, 2);
  1383.     }
  1384.  
  1385.     gcv.foreground = gcv.background = bcolor;
  1386.     gcmv.foreground = gcmv.background = 0;
  1387.     erasegc = XCreateGC(dpy, draw_pm, GCForeground | GCBackground | GCFont, &gcmv);
  1388.     bggc = XCreateGC(dpy, main_win, GCForeground | GCBackground | GCFont, &gcv);
  1389.  
  1390.     /* Clear out action pixmap */
  1391.     XFillRectangle(dpy, acts_pm, erasegc, 0, 0, B_WID, B_HT);
  1392.  
  1393.     startup_pm = get_pixmap(startup_bits, startup_width, startup_height, FALSE);
  1394.     draw_startup_picture();
  1395.  
  1396.     /* Use a cross cursor for the draw window */
  1397.     cross = XCreateFontCursor(dpy, XC_tcross);
  1398.  
  1399.     /* Set window event masks and other attributes */
  1400.     xswa.event_mask = ExposureMask | StructureNotifyMask;
  1401.     XChangeWindowAttributes(dpy, main_win, CWEventMask, &xswa);
  1402.  
  1403.     xswa.event_mask = KeyPressMask | ExposureMask;
  1404.     XChangeWindowAttributes(dpy, text_win, CWEventMask, &xswa);
  1405.  
  1406.     xswa.event_mask = ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | KeyPressMask | ExposureMask;
  1407.     XChangeWindowAttributes(dpy, acts_win, CWEventMask, &xswa);
  1408.     xswa.cursor = cross;
  1409.     XChangeWindowAttributes(dpy, draw_win, CWEventMask | CWCursor, &xswa);
  1410.  
  1411.     XMapWindow(dpy, draw_win);
  1412.     XMapWindow(dpy, text_win);
  1413.     XMapWindow(dpy, acts_win);
  1414.  
  1415.     XFlush(dpy);
  1416. }
  1417.  
  1418. static void make_widgets()
  1419. {
  1420.     int i, y;
  1421.  
  1422.     {    
  1423.     Pixmap title_pm = get_pixmap(title_bits, title_width, title_height, FALSE);
  1424.     XCopyArea(dpy, title_pm, acts_pm, drawgc, 0, 0, title_width, title_height, 4, 4);
  1425.     XFreePixmap(dpy, title_pm);
  1426.     }
  1427.  
  1428.     add_modebutton(acts_pm, acts_win, B_WID/2, 4, B_WID-6, 54, "Edit", edit_bits, edit_width, edit_height, M_EDIT, &mode, FALSE);
  1429.     add_modebutton(acts_pm, acts_win, 4, 54, B_WID/2, 104, "Mass", mass_bits, mass_width, mass_height, M_MASS, &mode, FALSE);
  1430.     add_modebutton(acts_pm, acts_win, B_WID/2, 54, B_WID-6, 104, "Spring", spring_bits, spring_width, spring_height, M_SPRING, &mode, FALSE);
  1431.  
  1432.     add_slider(acts_pm, acts_win, 4, 110, B_WID-6, 125, "Mass", "%10.2lf", S_MASS, &(mst.cur_mass), 10000000.0, 0.01, 0.01);
  1433.     add_slider(acts_pm, acts_win, 4, 127, B_WID-6, 142, "Elasticity", "%10.3lf", S_ELAS, &(mst.cur_rest), 1.0, 0.0, 0.001);
  1434.     add_slider(acts_pm, acts_win, 4, 144, B_WID-6, 159, "Kspring", "%10.2lf", S_KSPR, &(mst.cur_ks), 10000000.0, 0.01, 0.01);
  1435.     add_slider(acts_pm, acts_win, 4, 161, B_WID-6, 176, "Kdamp", "%10.2lf", S_KDAMP, &(mst.cur_kd), 10000000.0, 0.0, 0.01);
  1436.  
  1437.     add_checkbox(acts_pm, acts_win, 4, 178, B_WID/2-16, 194, "Fixed Mass", C_FIXEDMASS, &(mst.fix_mass));
  1438.     add_checkbox(acts_pm, acts_win, B_WID/2, 178, B_WID-6, 194, "Show Springs", C_SHOWSPRING, &(mst.show_spring));
  1439.  
  1440.     add_button(acts_pm, acts_win, 4, 197, B_WID/2 + 10, 217, "Set Rest Length", B_RESTLEN);
  1441.     add_button(acts_pm, acts_win, B_WID/2 + 16, 197, B_WID-6, 217, "Set Center", B_CENTER);
  1442.  
  1443.     y = 228;
  1444.     XDrawLine(dpy, acts_pm, drawgc, 0, y-4, B_WID-1, y-4);
  1445.     y++;
  1446.  
  1447.     for (i = 0; i < BF_NUM; i++) {
  1448.     mst.bf_mode[i] = -1;
  1449.     add_modebutton(acts_pm, acts_win, i*(BF_SIZ+4)+4, y, 4+(i+1)*(BF_SIZ+4),y+BF_SIZ+4,"", b_bits[i], BF_SIZ, BF_SIZ, M_BF + i, &(mst.bf_mode[i]), TRUE);
  1450.     }
  1451.     force_liney = y;
  1452.  
  1453.     add_modebutton(acts_pm, acts_win, 132, y, 136+go_width, y+4+go_height, "", go_bits, go_width, go_height, M_ACTION, &action, TRUE);
  1454.  
  1455.     y += 36;
  1456.     add_slider(acts_pm, acts_win, 4, y, B_WID-6, y+15, "", "%10.2lf", S_GRAV, &(mst.cur_grav_val[0]), cur_grav_max[0], cur_grav_min[0], 0.01);
  1457.     grav_slidx = 4;
  1458.     grav_slidy = (y + y+15 + F_HT) / 2 - 2;
  1459.  
  1460.     add_slider(acts_pm, acts_win, 4, y+17, B_WID-6, y+32, "", "%10.2lf", S_GDIR, &(mst.cur_grav_val[0]), cur_misc_max[0], cur_misc_min[0], 0.05);
  1461.  
  1462.     dir_slidx = 4;
  1463.     dir_slidy = (y+17 + y+32 + F_HT) / 2 - 2;
  1464.     update_slidnum(0);
  1465.  
  1466.     y += 38;
  1467.     XDrawLine(dpy, acts_pm, drawgc, 0, y - 4, B_WID-1, y - 4);
  1468.  
  1469.     add_slider(acts_pm, acts_win, 4, y, B_WID-6, y+15, "Viscosity", "%10.2lf", S_VISC, &(mst.cur_visc), 10000000.0, 0.0, 0.01);
  1470.     add_slider(acts_pm, acts_win, 4, y+17, B_WID-6, y+32, "Stickiness", "%10.2lf", S_STICK, &(mst.cur_stick), 10000000.0, 0.0, 0.01);
  1471.  
  1472.     y = y + 37;
  1473.  
  1474.     XDrawLine(dpy, acts_pm, drawgc, 0, y - 4, B_WID-1, y - 4);
  1475.  
  1476.     add_slider(acts_pm, acts_win, 4, y, B_WID-6, y+15, "Time Step", "%10.4lf", S_TIMESTEP, &(mst.cur_dt), 1.0, 0.0001, 0.0001);
  1477.     add_slider(acts_pm, acts_win, 4, y+17, B_WID-6, y+32, "Precision", "%10.4lf", S_PRECISION, &(mst.cur_prec), 1000.0, 0.0001, 0.0001);
  1478.     add_checkbox(acts_pm, acts_win, 4, y+33, B_WID/2+32, y+49, "Adaptive Time Step", C_ADAPTIVE_STEP, &(mst.adaptive_step));
  1479.  
  1480.     y = y + 54;
  1481.     XDrawLine(dpy, acts_pm, drawgc, 0, y-4, B_WID-1, y-4);
  1482.  
  1483.     add_slider(acts_pm, acts_win, 4, y, B_WID/2 + 20, y+16, "", "%10.0lf", S_GRIDSNAP, &(mst.cur_gsnap), 200.0, 1.0, 1.0);
  1484.     add_checkbox(acts_pm, acts_win, B_WID/2 + 24, y, B_WID - 4, y+16, "Grid Snap", C_GRIDSNAP, &(mst.grid_snap));
  1485.  
  1486.     y = y + 2;
  1487.     XDrawRectangle(dpy, acts_pm, drawgc, 16, y+24, 64, 30);
  1488.     add_checkbox(acts_pm, acts_win, 40, y+18, 56, y+33, "", C_WTOP, &(mst.w_top));
  1489.     add_checkbox(acts_pm, acts_win, 8, y+33, 24, y+48, " Walls", C_WLEFT, &(mst.w_left));
  1490.     add_checkbox(acts_pm, acts_win, 72, y+33, 88, y+48, "", C_WRIGHT, &(mst.w_right));
  1491.     add_checkbox(acts_pm, acts_win, 40, y+48, 56, y+63, "", C_WBOTTOM, &(mst.w_bottom));
  1492.  
  1493.     y = y + 16;
  1494.     add_button(acts_pm, acts_win, B_WID/2+3, y, B_WID-6, y+20, "Delete", B_DELETE);
  1495.     add_button(acts_pm, acts_win, B_WID/2+3, y+25, B_WID-6, y+45, "Select all", B_SELECTALL);
  1496.  
  1497.     y = y + 52;
  1498.     XDrawLine(dpy, acts_pm, drawgc, 0, y-3, B_WID-1, y-3);
  1499.  
  1500.     add_button(acts_pm, acts_win, 4, y, B_WID/2-5, y+20, "Save State", B_SAVESTATE);
  1501.     add_button(acts_pm, acts_win, B_WID/2+3, y, B_WID-6, y+20, "Restore State", B_RESSTATE);
  1502.     add_button(acts_pm, acts_win, 4, y+25, B_WID/2-5, y+45, "Duplicate", B_DUPLICATE);
  1503.     add_button(acts_pm, acts_win, B_WID/2+3, y+25, B_WID-6, y+45, "Insert File", B_INSERTFILE);
  1504.  
  1505.     add_button(acts_pm, acts_win, 4, y+50, B_WID/2-5, y+70, "Load File", B_LOADFILE);
  1506.     add_button(acts_pm, acts_win, B_WID/2+3, y+50, B_WID-6, y+70, "Save File", B_SAVEFILE);
  1507.     add_button(acts_pm, acts_win, 4, y+75, B_WID/2-5, y+95, "Reset", B_RESET);
  1508.     add_button(acts_pm, acts_win, B_WID/2+3, y+75, B_WID-6, y+95, "Quit", B_QUIT);
  1509.  
  1510.     slid_dt_num = slider_valno(S_TIMESTEP);
  1511. }
  1512.  
  1513. void usage()
  1514. {
  1515.     static char *msg1 = "Usage: xspringies [-d|display displayname] [-geometry geom] [-rv]\n";
  1516.     static char *msg2 = "                  [-bg color] [-fg color] [-hl color] [-st int] [-nbb]\n";
  1517.  
  1518.     fprintf(stderr, msg1);
  1519.     fprintf(stderr, msg2);
  1520.     exit(-1);
  1521. }
  1522.  
  1523. main(argc, argv)
  1524. int argc;
  1525. char *argv[];
  1526. {
  1527.     char *swch, *displayname = NULL, *geometry = NULL, *bgcolor = "black", *fgcolor = "white", *hlcolor = NULL;
  1528.     boolean rev_vid = FALSE;
  1529.     extern char *getenv();
  1530.     char *path;
  1531.  
  1532.     initst = sst = mst;
  1533.  
  1534.     if ((path = getenv("SPRINGDIR")) != NULL) {
  1535.     strcpy(filename, path);
  1536.     } else {
  1537.     strcpy(filename, DEF_PATH);
  1538.     }
  1539.  
  1540.     while (--argc > 0) {
  1541.     if (**++argv == '-') {
  1542.         swch = (*argv) + 1;
  1543.  
  1544.         if (!strcmp(swch, "display") || !strcmp(swch, "d")) {
  1545.         if (--argc > 0) {
  1546.             displayname = *++argv;
  1547.         } else {
  1548.             usage();
  1549.         }
  1550.         } else if (!strcmp(swch, "geometry")) {
  1551.         if (--argc > 0) {
  1552.             geometry = *++argv;
  1553.         } else {
  1554.             usage();
  1555.         }
  1556.         } else if (!strcmp(swch, "rv")) {
  1557.         rev_vid = TRUE;
  1558.         } else if (!strcmp(swch, "bg")) {
  1559.         if (--argc > 0) {
  1560.             bgcolor = *++argv;
  1561.         } else {
  1562.             usage();
  1563.         }
  1564.         } else if (!strcmp(swch, "fg")) {
  1565.         if (--argc > 0) {
  1566.             fgcolor = *++argv;
  1567.         } else {
  1568.             usage();
  1569.         }
  1570.         } else if (!strcmp(swch, "hl")) {
  1571.         if (--argc > 0) {
  1572.             hlcolor = *++argv;
  1573.         } else {
  1574.             usage();
  1575.         }
  1576.         } else if (!strcmp(swch, "st")) {
  1577.         if (--argc > 0) {
  1578.             spthick = atoi(*++argv);
  1579.             if (spthick < 0) {
  1580.             fprintf(stderr, "String thickness value must be non-negative\n");
  1581.             exit(-1);
  1582.             }
  1583.         } else {
  1584.             usage();
  1585.         }
  1586.         } else if (!strcmp(swch, "nbb")) {
  1587.         bboxing = FALSE;
  1588.         } else {
  1589.         usage();
  1590.         }
  1591.     } else {
  1592.         usage();
  1593.     }
  1594.     }
  1595.  
  1596.     if (rev_vid) {
  1597.     char *swap = fgcolor;
  1598.  
  1599.     fgcolor = bgcolor;
  1600.     bgcolor = swap;
  1601.     }
  1602.  
  1603.     init_x(argc, argv, displayname, geometry, fgcolor, bgcolor, hlcolor);
  1604.  
  1605.     init_widgets(widget_notify);
  1606.     make_widgets();
  1607.  
  1608.     init_objects();
  1609.  
  1610.     while (x_event());
  1611.  
  1612.     clean_up();
  1613.     return 0;
  1614. }
  1615. \BARFOO\
  1616. else
  1617.   echo "will not over write ./xdisp.c"
  1618. fi
  1619. echo "Finished archive 2 of 16"
  1620. exit
  1621.  
  1622. exit 0 # Just in case...
  1623. -- 
  1624.   // chris@IMD.Sterling.COM            | Send comp.sources.x submissions to:
  1625. \X/  Amiga - The only way to fly!      |
  1626.  "It's intuitively obvious to the most |    sources-x@imd.sterling.com
  1627.   casual observer..."                  |
  1628.