home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3407 / x.c < prev   
Encoding:
C/C++ Source or Header  |  1991-05-24  |  22.1 KB  |  902 lines

  1.  
  2. #include <X11/Xlib.h>
  3. #include <X11/Xutil.h>
  4. #include <X11/Xos.h>
  5. #include <sys/types.h>
  6. #include <sys/time.h>
  7. #include <sys/resource.h>
  8. #include <sys/param.h>
  9. #include <termio.h>
  10. #include <stdio.h>
  11. #include <strings.h>
  12. #include "mb.h"
  13. #include "cmap.h"
  14. #include "misc.h"
  15. #include "pix.h"
  16.  
  17. #ifdef USE_NETWORK
  18. #include "ipc.h"
  19. #endif
  20.  
  21. #define GEOM_PLACE 1
  22. #define GEOM_RIGHT 2
  23. #define GEOM_DOWN 4
  24. #define GEOM_SIZE 8
  25. #define GEOM_ERROR 16
  26.  
  27. /* Just to make sure that the number of colors will be reasonable
  28.  * on a 24-bit true-color display ;)
  29.  */
  30. #define MAXCOLORS 1024
  31.  
  32. /* dummy procedure for XCheckIfEvent */
  33. Bool dummy() {return(1);}
  34.  
  35. #ifdef USE_NETWORK
  36. /* Terminology: server is the one who shows pictures, and
  37.  * clients do the calculations. 
  38.  */
  39.  
  40. #define MODE_STANDALONE 0
  41. #define MODE_SERVER 1
  42. #define MODE_CLIENT 2
  43.  
  44. #define RSHCMD "rsh %s \"xnetmb -nice 10 -port %d -server %s&\" </dev/null >/dev/null"
  45. #endif
  46.  
  47. static Display *display;
  48. static int screen;
  49. static Window win= 0, cwin= 0;
  50. static GC gc, gc_inv, gc_set, gc_clear;
  51. #ifdef USE_NETWORK
  52. static int mode= MODE_STANDALONE;
  53. static int portnum= DEF_PORT;
  54. static char *server;
  55. #endif
  56.  
  57. void DrawSplitImage();
  58. void CalcImage();
  59. void DrawImage();
  60. void DrawRect();
  61. #define EraseRect() DrawRect(0, 0,0, 0,0, 0,0);
  62.  
  63. static double xc= 0.0, yc= 0.0, cx= 0.0, cy= 0.0, d= 0.0, scale= 8.0;
  64. static int iter= 500, flags= 0;
  65. unsigned int width= 300, height= 300;
  66.  
  67.  
  68. int ParseComplex(string, x, y)
  69. char *string;
  70. double *x, *y;
  71. {
  72. char ii, sign;
  73. /* x+-yi */
  74. if (sscanf(string, "%lf%lf%c", x, y, &ii) == 3 &&
  75.     ii == 'i')
  76.   ;
  77. /* x+-iy  */
  78. else if (sscanf(string, "%lf%ci%lf", x, &sign, y) == 3 &&
  79.          (sign == '+' || sign == '-')) {
  80.   if  (sign == '-') *y = -*y;
  81.   }
  82. /* x+-i */
  83. else if (sscanf(string, "%lf%c%c", x, &sign, &ii) == 3 &&
  84.          (sign == '+' || sign == '-') && ii == 'i') {
  85.   if (sign == '-')
  86.     *y= -1.0;
  87.   else
  88.     *y= 1.0;
  89.   }
  90. /* +-iy */
  91. else if (sscanf(string, "%c%c%lf", &ii, &sign, y) == 3 &&
  92.       (sign == '+' || sign == '-') && ii == 'i') {
  93.   *x= 0.0;
  94.   if (sign == '-')
  95.     *y= -*y;
  96.   }
  97. /* yi */
  98. else if (sscanf(string, "%lf%c", y, &ii) == 2 && ii == 'i')
  99.   *x= 0.0;
  100. /* iy */
  101. else if (sscanf(string, "%c%lf", &ii, y) == 2 && ii == 'i')
  102.   *x= 0.0;
  103. /* +-i */
  104. else if (sscanf(string, "%c%c", &sign, &ii) == 2 &&
  105.       (sign == '-' || sign == '+') && ii == 'i') {
  106.   *x= 0.0;
  107.   if (sign == '-')
  108.     *y= -1.0;
  109.   else
  110.     *y= 1.0;
  111.   }
  112. /* i */
  113. else if (sscanf(string, "%c", &ii) == 1 && ii == 'i') {
  114.   *x= 0.0;
  115.   *y= 1.0;
  116.   }
  117. /* x */
  118. else if (sscanf(string, "%lf", x) == 1)
  119.   *y= 0.0;
  120. else
  121.   return(0);
  122. return(1);
  123. }
  124.  
  125.  
  126. main(argc, argv)
  127. int argc;
  128. char *argv[];
  129. {
  130. XSizeHints size_hints;
  131. XEvent event;
  132. XGCValues gcval;
  133. XWindowAttributes xwattr;
  134. XSetWindowAttributes xswattr;
  135. unsigned int border_width= 1;
  136. unsigned int display_width, display_height;
  137. int win_x= 0, win_y= 0;
  138. int cwin_x= 0, cwin_y= 0;
  139. int dragx, dragy;
  140. int buttonpressed;
  141. int ncolors= 0;
  142. int zebra= 0;
  143. double xstore1= xc, ystore1= yc, scalestore1= scale;
  144. double xstore2= xc, ystore2= yc, scalestore2= scale;
  145. int flagstore= flags;
  146. int wingeom= 0;
  147. char **mach;
  148. int nmach= 0;
  149. char *window_name= "XMandelbrot";
  150. char *icon_name= "XMandel";
  151. char *cwindow_name= "MBcolors";
  152. char *cicon_name= "MBcolors";
  153. char *display_name= NULL;
  154.  
  155. int i;
  156.  
  157. /* Command line options... boring.
  158.  * (OH NO, it is my pseudo-intelligent commenting style attack again.
  159.  * Sigh... Please be patient and hope for the best.)
  160.  */
  161. for (i= 1; i < argc; i++) {
  162.   if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "-display")) {
  163.     if (++i >= argc) {
  164.       fprintf(stderr, "%s: error in cmd line option 'display'\n",
  165.           argv[0]);
  166.       exit(1);
  167.       }
  168.     display_name= argv[i];
  169.     }
  170.  
  171.   else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "-geometry")) {
  172.     char sign1, sign2;
  173.     if (++i >= argc) {
  174.       fprintf(stderr, "%s: error in cmd line option 'geometry'\n",
  175.           argv[0]);
  176.       exit(1);
  177.       }
  178.     switch (sscanf(argv[i], "%ux%u%c%d%c%d",
  179.         &width, &height, &sign1, &win_x, &sign2, &win_y)) {
  180.       case 6:
  181.         wingeom= GEOM_PLACE | GEOM_SIZE;
  182.         if (sign1 == '-') wingeom |= GEOM_RIGHT;
  183.         else if (sign1 != '+') wingeom |= GEOM_ERROR;
  184.         if (sign2 == '-') wingeom |= GEOM_DOWN;
  185.         else if (sign2 != '+') wingeom |= GEOM_ERROR;
  186.         if (wingeom & GEOM_ERROR) {
  187.           fprintf(stderr,
  188.               "%s: error in cmd line option 'geometry'\n",
  189.                   argv[0]);
  190.           exit(1);
  191.           }
  192.         break;
  193.       case 2:
  194.         wingeom= GEOM_SIZE;
  195.         /* There is nothing else here to be done. */
  196.         break;
  197.       default:
  198.         fprintf(stderr, "%s: error in cmd line option 'geometry'\n",
  199.             argv[0]);
  200.         exit(1);
  201.       }
  202.     }
  203.  
  204.   else if (!strcmp(argv[i], "-z") || !strcmp(argv[i], "-zebra")) {
  205.     /* Need to know which of the two -z options this is... */
  206.     if (!strcmp(argv[i], "-z") && i+1 < argc &&
  207.         ParseComplex(argv[i+1], &xc, &yc)) {
  208.       i++;
  209.       xstore1= xc; ystore1= yc;
  210.       }
  211.     else
  212.       zebra= 1;
  213.     }
  214.  
  215.   else if (!strcmp(argv[i], "-n") || !strcmp(argv[i], "-nice")) {
  216.     if (++i >= argc) {
  217.       fprintf(stderr, "%s: error in cmd line option 'nice'\n",
  218.           argv[0]);
  219.       exit(1);
  220.       }
  221.     setpriority(PRIO_PROCESS,getpid(), atoi(argv[i]));
  222.     }
  223.  
  224.   else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "-iters")) {
  225.     if (++i >= argc) {
  226.       fprintf(stderr, "%s: error in cmd line option 'iters'\n",
  227.           argv[0]);
  228.       exit(1);
  229.       }
  230.     iter= atoi(argv[i]);
  231.     }
  232.  
  233.   else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "-colors")) {
  234.     if (++i >= argc) {
  235.       fprintf(stderr, "%s: error in cmd line option 'colors\n",
  236.           argv[0]);
  237.       exit(1);
  238.       }
  239.     ncolors= atoi(argv[i]);
  240.     if (ncolors < 2)
  241.       ncolors= 2;
  242.     }
  243.  
  244.   else if (!strcmp(argv[i], "-j")) {
  245.     if (++i >= argc || !ParseComplex(argv[i], &cx, &cy)) {
  246.       fprintf(stderr, "%s: error in cmd line option 'j'\n",
  247.               argv[0]);
  248.       exit(1);
  249.       }
  250.     flagstore = (flags |= JULIA);
  251.     }
  252.  
  253.   else if (!strcmp(argv[i], "-x")) {
  254.     if (++i >= argc || sscanf(argv[i], "%lf", &scale) < 1) {
  255.       fprintf(stderr, "%s: error in cmd line option 'x'\n",
  256.               argv[0]);
  257.       exit(1);
  258.       }
  259.     scalestore1 = (scale *= 2);
  260.     }
  261.       
  262. #ifdef USE_NETWORK
  263.   else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "-server")) {
  264.     int k;
  265.     if (++i >= argc || mode != MODE_STANDALONE) {
  266.       fprintf(stderr, "%s: error in cmd line option 'server'\n",
  267.           argv[0]);
  268.       exit(1);
  269.       }
  270.     /* We are the client, and server is specified here. */
  271.     mode= MODE_CLIENT;
  272.     server= argv[i];
  273.     /* daemon  */
  274.     for (k= getdtablesize() - 1; k >= 0; --k)
  275.       close(k);
  276.     k= open("/dev/null", O_RDONLY);
  277.     if (k >= 0) {
  278.       ioctl(k, TIOCNOTTY, 0);
  279.       close(k);
  280.       }
  281.     }
  282. #endif
  283.  
  284. #ifdef USE_NETWORK
  285.   else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "-port")) {
  286.     if (++i >= argc) {
  287.       fprintf(stderr, "%s: error in cmd line option 'iters'\n",
  288.           argv[0]);
  289.       exit(1);
  290.       }
  291.     portnum= atoi(argv[i]);
  292.     }
  293. #endif
  294.  
  295. #ifdef USE_NETWORK
  296.   else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "-machines")) {
  297.     if (mode != MODE_STANDALONE) {
  298.       fprintf(stderr, "%s: error in command line option 'machines'\n",
  299.         argv[0]);
  300.       exit(1);
  301.       }
  302.       
  303.     mode= MODE_SERVER;
  304.     mach= &argv[i+1];
  305.     while (++i < argc && argv[i][0] != '-')
  306.       nmach++;
  307.     --i;
  308.     }
  309. #endif
  310.  
  311.   else if (!strcmp(argv[i], "-guru")) {
  312.     if (++i >= argc) {
  313.       fprintf(stderr, "%s: You are not a guru.\n", argv[0]);
  314.       exit(1);
  315.       }
  316.     if (!strcmp(argv[i], "fast")) {
  317.       flagstore= (flags |= FAST);
  318.       }
  319.     else {
  320.       fprintf(stderr, "%s: You are not a guru.\n", argv[0]);
  321.       exit(1);
  322.       }
  323.     }
  324.  
  325.   else {
  326.     fprintf(stderr, "%s: unrecognized cmd line option '%s'\n\n",
  327.             argv[0], argv[i]);
  328.     fprintf(stderr,
  329.             "Usage: %s -display <name> -geometry <geometry>\n",
  330.         argv[0]);
  331.     fprintf(stderr,
  332.             "-zebra -nice <value> -iters <i> -colors <number>\n");
  333.     fprintf(stderr,
  334.             "-z <x+yi> -j <cx+cyi> -x <scale>\n");
  335. #ifdef USE_NETWORK
  336.     fprintf(stderr,
  337.             "-server <name> -port <port> -machines [list of rsh machines]\n");
  338. #endif
  339.     fprintf(stderr, "\nAll options may be abbreviated.\n\n");
  340.     exit(1);
  341.     }
  342.   } /* for */
  343.  
  344. #ifdef USE_NETWORK
  345. if (mode == MODE_CLIENT) {
  346.   Client_run(server, portnum);
  347.   exit(0);
  348.   }
  349. else if (mode == MODE_SERVER) {
  350.   char cmd[sizeof(RSHCMD) + 2*MAXHOSTNAMELEN], host[MAXHOSTNAMELEN];
  351.   if (gethostname(host, MAXHOSTNAMELEN) < 0) {
  352.     perror("unable to find my name");
  353.     exit(1);
  354.     }
  355.   CreateServer(portnum);
  356.   printf("Starting remote machines:");
  357.   for (i= 0; i < nmach; i++) {
  358.     sprintf(cmd, RSHCMD, mach[i], portnum, host);
  359.     printf (" %s", mach[i]); fflush(stdout);
  360.     if ((system(cmd) >> 8) > 0) {
  361.       fprintf(stderr, "%s: unable to rsh %s\n", argv[0],
  362.           mach[i]);
  363.       }
  364.     }
  365.   --i;
  366.   putchar('\n');
  367.   }
  368. #endif
  369.  
  370. /* Open the display, if possible. */
  371. if(!(display= XOpenDisplay(display_name))) {
  372.   fprintf(stderr, "cannot reach X server %s\n",
  373.         XDisplayName(display_name));
  374.   exit(1);
  375.   }
  376.  
  377. screen= DefaultScreen(display);
  378.  
  379. display_width= DisplayWidth(display, screen);
  380. display_height= DisplayHeight(display, screen);
  381.  
  382. if (!(wingeom & GEOM_PLACE)) {
  383.   win_x= display_width / 2 - (int)width;
  384.   win_y= 2 * display_height / 3;
  385.   }
  386. else {
  387.   if (wingeom & GEOM_RIGHT) win_x= (int)display_width - win_x - (int)width;
  388.   if (wingeom & GEOM_DOWN) win_y= (int)display_height - win_y - (int)height;
  389.   }
  390.  
  391. cwin_x= display_width / 2 - 200;
  392. cwin_y= display_height - 250;
  393.  
  394.  
  395. if (ncolors == 0)
  396.   ncolors= 1 << (DefaultDepth(display, screen));
  397. if (zebra) ncolors= 3;
  398. if (ncolors > MAXCOLORS)
  399.   ncolors= MAXCOLORS;
  400. SetNColors(ncolors);
  401.  
  402. xswattr.background_pixel= WhitePixel(display, screen);
  403. xswattr.border_pixel= BlackPixel(display, screen);
  404. win= XCreateWindow(display, RootWindow(display, screen), win_x, win_y,
  405.                     width, height, border_width, CopyFromParent,
  406.                     InputOutput, CopyFromParent,
  407.                     CWBackPixel | CWBorderPixel, &xswattr);
  408. cwin= XCreateWindow(display, RootWindow(display, screen), cwin_x, cwin_y,
  409.                      400, 200, border_width, CopyFromParent,
  410.                      InputOutput, CopyFromParent,
  411.                      CWBackPixel | CWBorderPixel, &xswattr);
  412.  
  413. if (!win  || !cwin) {
  414. #ifdef USE_NETWORK
  415.   if (mode == MODE_SERVER)
  416.     CloseDown();
  417. #endif
  418.   perror("could not open window");
  419.   myExit();
  420.   exit(0);
  421.   }
  422.  
  423. size_hints.flags= PMinSize;
  424. if (wingeom & GEOM_PLACE) size_hints.flags |= PPosition;
  425. if (wingeom & GEOM_SIZE) size_hints.flags |= PSize;
  426.  
  427. size_hints.width= width;
  428. size_hints.height= height;
  429. size_hints.min_width= 50;
  430. size_hints.min_height= 50;
  431. size_hints.x= win_x;
  432. size_hints.y= win_y;
  433. XSetStandardProperties(display, win, window_name, icon_name,
  434.                        None, NULL, 0, &size_hints);
  435.  
  436. size_hints.flags= PPosition | PSize | PMinSize;
  437. size_hints.width= 400;
  438. size_hints.height= 200;
  439. size_hints.min_width= 200;
  440. size_hints.min_height= 100;
  441. size_hints.x= cwin_x;
  442. size_hints.y= cwin_y;
  443. XSetStandardProperties(display, cwin, cwindow_name, cicon_name,
  444.                        None, NULL, 0, &size_hints);
  445.  
  446. XSelectInput(display, win, ExposureMask | KeyPressMask |
  447.              ButtonPressMask | ButtonReleaseMask |
  448.              PointerMotionMask | StructureNotifyMask);
  449. XSelectInput(display, cwin, ExposureMask | KeyPressMask |
  450.              ButtonPressMask | ButtonReleaseMask |
  451.              PointerMotionMask | StructureNotifyMask);
  452.  
  453. gcval.foreground= BlackPixel(display, screen);
  454. gcval.background= WhitePixel(display, screen);
  455. gc= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
  456. gc_set= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
  457.  
  458. gcval.foreground= WhitePixel(display, screen);
  459. gc_clear= XCreateGC(display, win, GCForeground | GCBackground, &gcval);
  460.  
  461. gcval.function= GXinvert;
  462. gc_inv= XCreateGC(display, win, GCFunction, &gcval);
  463.  
  464. if (!AllocFonts(display, gc_set)) {
  465.   fprintf(stderr, "Could not open fonts... no text will be drawn");
  466.   }
  467. AllocColors(display, screen);
  468.  
  469. AllocCursors(display);
  470. NormalCursor(display, win);
  471. NormalCursor(display, cwin);
  472.  
  473. XMapWindow(display, win);
  474. buttonpressed= 0;
  475.  
  476. for (;;) {
  477. #ifdef USE_NETWORK
  478.   if (mode == MODE_SERVER) 
  479.     CheckClients(NOBLOCK);
  480.  
  481.   if (mode == MODE_SERVER && PendingRequests()) {
  482.     while (!XCheckIfEvent(display, &event, dummy, (char *)NULL)) 
  483.       CheckClients(1);
  484.     if (!PendingRequests()) {
  485.       NormalCursor(display, win);
  486.       NormalCursor(display, cwin);
  487.       }
  488.     }
  489.   else 
  490.     XNextEvent(display, &event);
  491. #else
  492.   XNextEvent(display, &event);
  493. #endif
  494.  
  495.   if (event.xany.window == cwin) {
  496.     switch (HandleCEvent(display, screen, cwin, gc,
  497.                   gc_set, gc_clear, &event)) {
  498.       case DO_REDRAW:
  499. #ifdef USE_NETWORK
  500.             if (mode == MODE_SERVER) Invalidate();
  501. #endif
  502.         XClearArea(display, win, 0, 0, width, height, 1);
  503.         break;
  504.       case DO_PREVIOUS:
  505.         if (xc != xstore1 || yc != ystore1 ||
  506.             scale != scalestore1 || flags != flagstore) {
  507.           xc= xstore1; yc= ystore1;
  508.           scale= scalestore1;
  509.           flags= flagstore;
  510.           d= scale / (width + height);
  511. #ifdef USE_NETWORK
  512.             if (mode == MODE_SERVER) Invalidate();
  513. #endif
  514.           XClearArea(display, win, 0, 0, width, height, 1);
  515.           }
  516.         break;
  517.       case DO_RESTART:
  518.         xstore1= xc; ystore1= yc;
  519.         scalestore1= scale;
  520.         flagstore= flags;
  521.  
  522.         xc= 0.0; yc= 0.0;
  523.         scale= 8.0; flags &= ~JULIA;
  524.         d= scale / (width + height);
  525. #ifdef USE_NETWORK
  526.             if (mode == MODE_SERVER) Invalidate();
  527. #endif
  528.         XClearArea(display, win, 0, 0, width, height, 1);
  529.         break;
  530.         
  531.       case DO_QUIT:
  532. #ifdef USE_NETWORK
  533.       if (mode == MODE_SERVER)
  534.         CloseDown();
  535. #endif
  536.         myExit();
  537.         exit(0);
  538.       } /* switch */
  539.     }
  540.   else switch(event.type) {
  541.     case Expose:
  542.       WaitCursor(display, win);
  543.       WaitCursor(display, cwin);
  544.       CalcImage (event.xexpose.x, event.xexpose.y,
  545.                  event.xexpose.width, event.xexpose.height);
  546.       break;
  547.  
  548.     case ConfigureNotify:
  549. #ifdef USE_NETWORK
  550.       if (mode == MODE_SERVER) {
  551.         if (width != event.xconfigure.width ||
  552.             height != event.xconfigure.height)
  553.           Invalidate();
  554.         }
  555. #endif
  556.       width= event.xconfigure.width;
  557.       height= event.xconfigure.height;
  558.       d= scale / (width + height);
  559.       break;
  560.  
  561.     case ButtonPress: 
  562.       switch (event.xbutton.button) {
  563.         case 1: 
  564.           ZoomCursor(display, win);
  565.           dragx= event.xbutton.x;
  566.           dragy= event.xbutton.y;
  567.           buttonpressed= 1;
  568.           break;
  569.  
  570.         case 2: /* julia stuff here */
  571.           if (buttonpressed) {
  572.             EraseRect();
  573.             buttonpressed= 0;
  574.             NormalCursor(display, win);
  575.             }
  576.           else if (!(flags & JULIA)) {
  577.             /* toggle to julia set; save current context */
  578.             xstore1= xstore2= xc; ystore1= ystore2= yc;
  579.             scalestore1= scalestore2= scale;
  580.             flagstore= flags;
  581.  
  582.             flags |= JULIA;
  583.             cx= xc - d * (width/2.0 - event.xbutton.x);
  584.             cy= yc + d * (height/2.0 - event.xbutton.y);
  585.             xc= 0.0; yc= 0.0;
  586.             scale= 8.0;
  587.             d= scale / (width + height);
  588. #ifdef USE_NETWORK
  589.             if (mode == MODE_SERVER) Invalidate();
  590. #endif
  591.             XClearArea(display, win, 0, 0, width, height, 1);
  592.             }
  593.           else {
  594.             /* toggle to mb set; restore context */
  595.             xc= xstore2; yc= ystore2;
  596.             scale= scalestore2;
  597.             flags &= ~JULIA;
  598.             d= scale / (width + height);
  599. #ifdef USE_NETWORK
  600.             if (mode == MODE_SERVER) Invalidate();
  601. #endif
  602.             XClearArea(display, win, 0, 0, width, height, 1);
  603.             }
  604.           break;
  605.             
  606.         case 3: /* open colormap window */
  607.           if (buttonpressed) {
  608.             EraseRect();
  609.             buttonpressed= 0;
  610.             NormalCursor(display, win);
  611.             }
  612.           else
  613.             ToggleCWin(display, cwin, CMAP_TOGGLE);
  614.           break;
  615.         default: 
  616.           break;
  617.         }
  618.       break;
  619.  
  620.     case ButtonRelease:
  621.       switch (event.xbutton.button) {
  622.         case 1:
  623.           if (buttonpressed) {
  624.             int xdiff, ydiff;
  625.             xstore1= xc; ystore1= yc;
  626.             scalestore1= scale;
  627.             flagstore= flags;
  628.  
  629.             xdiff= dragx - event.xbutton.x;
  630.             ydiff= dragy - event.xbutton.y;
  631.             if (xdiff < 0) xdiff= -xdiff;
  632.             if (ydiff < 0) ydiff= -ydiff;
  633.             if (xdiff/(double)width < ydiff/(double)height)
  634.               scale *= (ydiff/(double)height);
  635.             else
  636.               scale *= (xdiff/(double)width);
  637.             buttonpressed= 0;
  638.             EraseRect();
  639.  
  640.             xc= xc - d * ((int)width - (dragx + event.xbutton.x)) / 2.0;
  641.             yc= yc + d * ((int)height - (dragy + event.xbutton.y)) / 2.0;
  642.             d= scale / (width + height);
  643. #ifdef USE_NETWORK
  644.             if (mode == MODE_SERVER) Invalidate();
  645. #endif
  646.             XClearArea(display, win, 0, 0, width, height, 1);
  647.             }
  648.         default:
  649.           break;
  650.         }
  651.       break;
  652.  
  653.     case MotionNotify:
  654.       if (buttonpressed)
  655.         DrawRect(1, dragx, dragy, event.xmotion.x, event.xmotion.y,
  656.                  (int)width, (int)height);
  657.       break;
  658.  
  659.     case KeyPress:
  660. #ifdef USE_NETWORK
  661.       if (mode == MODE_SERVER)
  662.         CloseDown();
  663. #endif
  664.       myExit();
  665.       exit(0);
  666.  
  667.     case MapNotify:
  668.       /* Determine size of set (depends on width & height) */
  669.       XGetWindowAttributes(display, win, &xwattr);
  670.       width= xwattr.width; height= xwattr.height;
  671.       d= scale / (width + height);
  672.       break;
  673.  
  674.     case ReparentNotify:
  675.     case UnmapNotify:
  676.       /* I can't think of anything reasonable to do here... */
  677.       break;
  678.  
  679.     default:
  680.       printf("Unknown Event %d\n", event.type);
  681.       break;
  682.     } /* switch */
  683.   } /* for(ever) */
  684. } /* main */
  685.  
  686.  
  687. myExit()
  688. {
  689. FreeFonts(display);
  690. XFreeGC(display, gc);
  691. XFreeGC(display, gc_inv);
  692. XFreeGC(display, gc_set);
  693. XFreeGC(display, gc_clear);
  694.  
  695. FreeColors(display, screen);
  696. if (win) XDestroyWindow(display, win);
  697. if (cwin) XDestroyWindow(display, cwin);
  698. XCloseDisplay(display);
  699. }
  700.  
  701.  
  702. /* Split the image into comfortably small chunks, which
  703.  * are then fed to DrawSplitImage() 
  704.  */
  705. void CalcImage(xoff, yoff, w, h)
  706. int xoff, yoff, w, h;
  707. {
  708. int xd=1, yd=1, xn, yn;
  709. /* do not accidentally crawl arond some area...
  710.  */
  711. if (xc - d*(width/2.0 - xoff) < -.5 &&
  712.     yc + d*(height/2.0 - yoff) > .5 &&
  713.     xc - d*(width/2.0 - xoff-w) > .5 &&
  714.     yc + d*(height/2.0 - yoff-h) < -.5) {
  715.   int x0= width/2 - xc/d;
  716.   int y0= height/2 + yc/d;
  717.   int xdist= x0 - xoff;
  718.   int ydist= y0 - yoff;
  719.   if (w > 2*xdist) xdist= w-xdist;
  720.   if (h > 2*ydist) ydist= h-ydist;
  721.   if (xdist > ydist) {
  722.     CalcImage(xoff, yoff, x0-xoff, h);
  723.     CalcImage(x0, yoff, w-(x0-xoff), h);
  724.     }
  725.   else {
  726.     CalcImage(xoff, yoff, w, y0-yoff);
  727.     CalcImage(xoff, y0, w, h-(y0-yoff));
  728.     }
  729.   return;
  730.   }  /* if */
  731. while (w*h/(xd*yd) > 65536) {
  732.   if (w*yd < h*xd) /* <==> w/xd<h/yd */
  733.     yd++;
  734.   else
  735.     xd++;
  736.   }
  737. for (yn= 0; yn < yd; yn++)
  738.   for (xn= 0; xn < xd; xn++) {
  739.     DrawSplitImage(xoff + xn*w/xd, yoff+yn*h/yd,
  740.               (xn+1)*w/xd - xn*w/xd,
  741.                    (yn+1)*h/yd - yn*h/yd);
  742.     }
  743. #ifdef USE_NETWORK
  744. if (mode == MODE_STANDALONE || !PendingRequests() ) {
  745.   NormalCursor(display, win);
  746.   NormalCursor(display, cwin);
  747.   }
  748. #else
  749. NormalCursor(display, win);
  750. NormalCursor(display, cwin);
  751. #endif
  752. }
  753.  
  754.  
  755. /* Calculate chunks either in local or in remote machines
  756.  */
  757. void DrawSplitImage(xoff, yoff, w, h)
  758. int xoff, yoff, w, h;
  759. {
  760. double x,y;
  761. u_short *dest;
  762. int tmpflags;
  763.  
  764. x= xc - d*(width/2.0 - xoff);
  765. y= yc + d*(height/2.0 - yoff);
  766.  
  767. XDrawRectangle(display, win, gc_set, xoff, yoff, w-1, h-1);
  768. XFlush(display);
  769.  
  770. #ifdef USE_NETWORK
  771. if (mode == MODE_SERVER)  {
  772.   /* Try to delegate */
  773.   if (CalcRequest(x, y, d, d, cx, cy, w, h, iter, flags, xoff, yoff))
  774.     return;
  775.   }
  776. #endif
  777. /* Always use FASTmode when using local machine */
  778. tmpflags= flags;
  779. flags |= FAST;
  780. iterate(x, y, d, d, cx, cy, w, h, iter, flags, &dest);
  781. DrawImage(xoff, yoff, w, h, dest);
  782. flags= tmpflags;
  783. }
  784.  
  785.  
  786. void DrawImage(xoff, yoff, w, h, dest)
  787. int xoff, yoff, w, h;
  788. u_short *dest;
  789. {
  790. int px, py;
  791. u_short *ptr, color;
  792. long len, i;
  793. XGCValues gcval;
  794. XPoint *xpts;
  795. long npts= 512;
  796. int fastmode= flags & FAST;
  797.  
  798. ptr= dest;
  799. xpts= (XPoint *)malloc(npts * sizeof(XPoint));
  800.  
  801. if (!fastmode)
  802.   initialize(w, h);
  803. for (;;) {
  804.   /* In fast mode, first_point() and next_point() are omitted.
  805.    * Server will be faster but there will be over 100% more traffic
  806.    * in the net.
  807.    */
  808.   if (fastmode) {
  809.     px= *ptr++;
  810.     if (px != LASTPIX)
  811.       py= *ptr++;
  812.     }
  813.   if (fastmode && px == LASTPIX)
  814.     break;
  815.   if (!fastmode && first_point(&px, &py) ==0)
  816.     break;
  817.   color= *ptr++;
  818.   gcval.foreground= ToPixel((int)(color & 0x7fff));
  819.   XChangeGC(display, gc, GCForeground, &gcval);
  820.  
  821.   if (color & 0x8000) {
  822.     XDrawPoint(display, win, gc, px+xoff, py+yoff);
  823.     }
  824.   else {
  825.     int dir, bitindex= 7;
  826.  
  827.     len= *ptr++;
  828.     if (len > npts) {
  829.       free(xpts);
  830.       xpts= (XPoint *)malloc((npts= len) * sizeof(XPoint));
  831.       }
  832.     for (i= 0; i < len; i++) {
  833.       dir= ((*ptr) >> (bitindex*2)) & 3;
  834.       if (!fastmode)
  835.         next_point(dir);
  836.  
  837.       XDrawPoint(display, win, gc, px+xoff, py+yoff);
  838.       xpts[i].x= px+xoff;
  839.       xpts[i].y= py+yoff;
  840.       switch (dir) {
  841.         case UP: py--; break;
  842.         case DOWN: py++; break;
  843.         case LEFT: px--; break;
  844.         case RIGHT: px++; break;
  845.         }
  846.       if (--bitindex < 0) {
  847.         ptr++;
  848.         bitindex= 7;
  849.         }
  850.       }
  851.     if (bitindex != 7)
  852.       ptr++;
  853.     XFillPolygon(display, win, gc, xpts, len, Complex, CoordModeOrigin);
  854.     } /* else */
  855.   } /* for */
  856. if (!fastmode)
  857.   deinit();
  858. free(dest);
  859. free(xpts);
  860. } /* DrawImage */
  861.  
  862.  
  863. void DrawRect(mode, x1, y1, x2, y2, w, h)
  864. int mode, x1, y1, x2, y2, w, h;
  865. {
  866. static int drawn= 0;
  867. static int dx, dy, dw, dh;
  868.  
  869. if (drawn)
  870.   XDrawRectangle(display, win, gc_inv, dx, dy, dw, dh);
  871. drawn= 0;
  872.  
  873. if (mode == 0)
  874.   return;
  875.  
  876. dw= x2 - x1; dh= y2 - y1;
  877. if (dw == 0 && dh == 0)
  878.   return;
  879.  
  880. dx= x1; dy= y1;
  881. if (dw < 0) {
  882.   dw= -dw;
  883.   dx= x2;
  884.   }
  885. if (dh < 0) {
  886.   dh= -dh;
  887.   dy= y2;
  888.   }
  889.  
  890. if (dw/(double)w > dh/(double)h) {
  891.   dh= dw * (h/(double)w);
  892.   dy= (y1 + y2 - dh)/2;
  893.   }
  894. else {
  895.   dw= dh * (w/(double)h);
  896.   dx= (x1 + x2 - dw)/2;
  897.   }
  898. XDrawRectangle(display, win, gc_inv, dx, dy, dw, dh);
  899. drawn= 1;
  900. } /* drawrect */
  901.  
  902.